Railway Operation Simulator  v2.6.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal): SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
74  else if(SpeedTagVal == 77)
76  else if(SpeedTagVal == 78)
78  else if(SpeedTagVal == 79)
80  else if(SpeedTagVal == 96)
82  else if(SpeedTagVal == 129)
84  else if(SpeedTagVal == 130)
86  else if(SpeedTagVal == 131)
88  else if(SpeedTagVal == 145)
90  else if(SpeedTagVal == 146)
92 }
93 
94 // ---------------------------------------------------------------------------
95 
96 TFixedTrackPiece::TFixedTrackPiece(): SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
97  FixedNamedLocationElement(false) // default values
98 {
99  for(int x = 0; x < 4; x++)
100  {
101  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
102  Config[x] = NotSet;
103  }
104 }
105 
106 // ---------------------------------------------------------------------------
107 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
108 {
109  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
110  AnsiString(VLocInput));
111  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
112  Utilities->CallLogPop(1331);
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 // VARIABLE TRACK :-
118 
119 // ---------------------------------------------------------------------------
120 
122 {
123  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
124  return true;
125  else
126  return false;
127 }
128 
129 // ---------------------------------------------------------------------------
130 
132 {
133  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
134  return true;
135  else
136  return false;
137 }
138 
139 // ---------------------------------------------------------------------------
140 
142  // 'Variable' in the sense that element might be striped or non-striped
143 {
144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
145  Graphics::TBitmap *GraphicOutput = GraphicPtr;
146 
147  if(LocationName == "")
148  {
149  switch(SpeedTag)
150  {
151  case 76: // t platform
152  GraphicOutput = RailGraphics->gl76Striped;
153  break;
154 
155  case 77: // h platform
156  GraphicOutput = RailGraphics->bm77Striped;
157  break;
158 
159  case 78: // v platform
160  GraphicOutput = RailGraphics->bm78Striped;
161  break;
162 
163  case 79: // r platform
164  GraphicOutput = RailGraphics->gl79Striped;
165  break;
166 
167  case 96: // concourse
168  GraphicOutput = RailGraphics->ConcourseStriped;
169  break;
170 
171  case 129: // v footbridge
172  GraphicOutput = RailGraphics->gl129Striped;
173  break;
174 
175  case 130: // h footbridge
176  GraphicOutput = RailGraphics->gl130Striped;
177  break;
178 
179  case 131: // non-station named loc
180  GraphicOutput = RailGraphics->bmNameStriped;
181  break;
182 
183  case 145: // v underpass
184  GraphicOutput = RailGraphics->gl145Striped;
185  break;
186 
187  case 146: // h underpass
188  GraphicOutput = RailGraphics->gl146Striped;
189  break;
190 
191  default:
192  GraphicOutput = GraphicPtr;
193  break;
194  }
195  }
196  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
197  Utilities->CallLogPop(1332);
198 }
199 
200 // ---------------------------------------------------------------------------
201 
202 AnsiString TTrackElement::LogTrack(int Caller) const
203  // for debugging when passes as a call parameter
204 {
205  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
206  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
207 
208  return LogString;
209 }
210 
211 // ---------------------------------------------------------------------------
212 
213 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
214 {
215  if(lower.second < higher.second)
216  {
217  return true;
218  }
219  else if(lower.second > higher.second)
220  {
221  return false;
222  }
223  else if(lower.second == higher.second)
224  {
225  if(lower.first < higher.first)
226  {
227  return true;
228  }
229  }
230  return false;
231 }
232 
233 // ---------------------------------------------------------------------------
234 // PrefDirElement Functions
235 // ---------------------------------------------------------------------------
236 
237 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
238  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
239  CheckCount(9), IsARoute(false), AutoSignals(false), ConsecSignals(false)
240 {
241  if(!EntryExitNumber())
242  {
243  throw Exception("EXNumber failure in TPrefDirElement constructor");
244  }
247 }
248 
249 // ---------------------------------------------------------------------------
250 
251 AnsiString TPrefDirElement::LogPrefDir() const
252  // for debugging when passed as a call parameter
253 {
254  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
255  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)ConsecSignals) +
256  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
257  AnsiString(TrainIDOnBridgeTrackPos23);
258 
259 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
260  return LogString;
261 }
262 
263 // ---------------------------------------------------------------------------
264 
265 bool TPrefDirElement::EntryExitNumber() // true for valid number
266 /*
267  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
268  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
269  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
270  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
271  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
272  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
273  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
274  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
275  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
276 */
277 
278 {
279  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
280  int EXArray[16][2] =
281  {{4, 6}, {2, 8}, // horizontal & vertical
282  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
283  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
284  {1, 9}, {3, 7}}; // forward & reverse diagonals
285 
286  int EXNum = -1;
287  int Entry, Exit;
288 
289  if(ELink > -1)
290  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
291  else if(Link[2] == -1)
292  Entry = Link[0];
293  else
294  {
295  Utilities->CallLogPop(122);
296  return false;
297  }
298  if(XLink > -1)
299  Exit = XLink;
300  else if(Link[2] == -1)
301  Exit = Link[1];
302  else
303  {
304  Utilities->CallLogPop(123);
305  return false;
306  }
307 
308  for(int x = 0; x < 16; x++)
309  {
310  if((Entry == EXArray[x][0]) && (Exit == EXArray[x][1]) || (Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))
311  {
312  EXNum = x;
313  }
314  }
315  if(EXNum == -1)
316  {
317  Utilities->CallLogPop(124);
318  return false;
319  }
320 
321  int BrNum = -1;
322 
323 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
324  the graphic for each of which is different because of the shape of the overbridge. The basic
325  entry/exit value is computed above, and this used to select only from elements with that entry/exit
326  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
327  int BrEXArray[24][2] = {
328  {4,6},{2,8},{1,9},{3,7},
329  {1,9},{3,7},{1,9},{3,7},
330  {2,8},{4,6},{2,8},{4,6}
331 */
332 
333  if(TrackType == Bridge)
334  {
335  if(EXNum == 1)
336  {
337  if(SpeedTag == 49)
338  BrNum = 1 + 16;
339  else if(SpeedTag == 54)
340  BrNum = 8 + 16;
341  else if(SpeedTag == 55)
342  BrNum = 10 + 16;
343  }
344  else if(EXNum == 0)
345  {
346  if(SpeedTag == 48)
347  BrNum = 0 + 16;
348  else if(SpeedTag == 58)
349  BrNum = 11 + 16;
350  else if(SpeedTag == 59)
351  BrNum = 9 + 16;
352  }
353  else if(EXNum == 14)
354  {
355  if(SpeedTag == 50)
356  BrNum = 2 + 16;
357  else if(SpeedTag == 52)
358  BrNum = 4 + 16;
359  else if(SpeedTag == 57)
360  BrNum = 6 + 16;
361  }
362  else if(EXNum == 15)
363  {
364  if(SpeedTag == 51)
365  BrNum = 3 + 16;
366  else if(SpeedTag == 53)
367  BrNum = 7 + 16;
368  else if(SpeedTag == 56)
369  BrNum = 5 + 16;
370  }
371  }
372  if(BrNum == -1)
373  EXNumber = EXNum;
374  else
375  EXNumber = BrNum;
376  Utilities->CallLogPop(125);
377  return true;
378 }
379 
380 // ---------------------------------------------------------------------------
381 
383 /*
384  This is the basic track graphic for use in plotting the original graphic during route flashing.
385  Enter with all set apart from EXGraphic & EntryDirectionGraphic
386 */
387 {
388  if(SpeedTag == 64)
389  return RailGraphics->LinkGraphicsPtr[16]; // intercept diagonal buffers
390 
391  if(SpeedTag == 65)
392  return RailGraphics->LinkGraphicsPtr[17];
393 
394  if(SpeedTag == 66)
395  return RailGraphics->LinkGraphicsPtr[18];
396 
397  if(SpeedTag == 67)
398  return RailGraphics->LinkGraphicsPtr[19];
399 
400  if(SpeedTag == 80)
401  return RailGraphics->LinkGraphicsPtr[20]; // intercept continuations
402 
403  if(SpeedTag == 81)
404  return RailGraphics->LinkGraphicsPtr[21];
405 
406  if(SpeedTag == 82)
407  return RailGraphics->LinkGraphicsPtr[22];
408 
409  if(SpeedTag == 83)
410  return RailGraphics->LinkGraphicsPtr[23];
411 
412  if(SpeedTag == 84)
413  return RailGraphics->LinkGraphicsPtr[24];
414 
415  if(SpeedTag == 85)
416  return RailGraphics->LinkGraphicsPtr[25];
417 
418  if(SpeedTag == 86)
419  return RailGraphics->LinkGraphicsPtr[26];
420 
421  if(SpeedTag == 87)
422  return RailGraphics->LinkGraphicsPtr[27];
423 
424  if(SpeedTag == 129)
425  return RailGraphics->LinkGraphicsPtr[28]; // intercept under footbridges
426 
427  if(SpeedTag == 130)
428  return RailGraphics->LinkGraphicsPtr[29];
429 
430  if(XLinkPos == -1) // not set, could be first element or last element = leading point
431  {
432 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
433 // Points & don't want to display these)
434  if(Link[2] != -1)
435  return 0; // i.e. complex element, don't display
436  else
437  {
438  if(!EntryExitNumber())
439  {
440  throw Exception("Error in EntryExitNumber 4");
441  }
442  else
443  {
445  }
446  }
447  }
448  if(EXNumber > 15) // underbridge
449  {
451  }
452  else
453  {
455  }
456 }
457 
458 // ---------------------------------------------------------------------------
459 
461 /*
462  As above but for PrefDir graphics.
463 */
464 {
465  if(SpeedTag == 64)
466  return RailGraphics->LinkPrefDirGraphicsPtr[16]; // intercept diagonal buffers
467 
468  if(SpeedTag == 65)
470 
471  if(SpeedTag == 66)
473 
474  if(SpeedTag == 67)
476 
477  if(SpeedTag == 80)
478  return RailGraphics->LinkPrefDirGraphicsPtr[20]; // intercept continuations
479 
480  if(SpeedTag == 81)
482 
483  if(SpeedTag == 82)
485 
486  if(SpeedTag == 83)
488 
489  if(SpeedTag == 84)
491 
492  if(SpeedTag == 85)
494 
495  if(SpeedTag == 86)
497 
498  if(SpeedTag == 87)
500 
501  if(SpeedTag == 129)
502  return RailGraphics->LinkPrefDirGraphicsPtr[28]; // intercept under footbridges
503 
504  if(SpeedTag == 130)
506 
507  if(XLinkPos == -1) // not set, could be first element or last element = leading point
508  {
509 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
510  if(Link[2] != -1)
511  return 0; // i.e. complex element, don't display
512  else
513  {
514  if(!EntryExitNumber())
515  {
516  throw Exception("Error in EntryExitNumber 5");
517  }
518  else
520  }
521  }
522  if(EXNumber > 15) // underbridge
523  {
525  }
526  else
528 }
529 
530 // ---------------------------------------------------------------------------
531 
532 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute)
533 /*
534  As above but for route graphics.
535 */
536 {
537  if(!AutoSigsFlag && !ConsecSignalsRoute)
538  {
539  if(SpeedTag == 64)
540  return RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers
541 
542  if(SpeedTag == 65)
544 
545  if(SpeedTag == 66)
547 
548  if(SpeedTag == 67)
550 
551  if(SpeedTag == 80)
552  return RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations
553 
554  if(SpeedTag == 81)
556 
557  if(SpeedTag == 82)
559 
560  if(SpeedTag == 83)
562 
563  if(SpeedTag == 84)
565 
566  if(SpeedTag == 85)
568 
569  if(SpeedTag == 86)
571 
572  if(SpeedTag == 87)
574 
575  if(SpeedTag == 129)
576  return RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
577 
578  if(SpeedTag == 130)
580 
581  if(XLinkPos == -1) // not set, could be first element or last element = leading point
582  {
583  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
584  if(Link[2] != -1)
585  return 0; // i.e. complex element, don't display
586  else
587  {
588  if(!EntryExitNumber())
589  {
590  throw Exception("Error in EntryExitNumber 6");
591  }
592  else
594  }
595  }
596  if(EXNumber > 15) // underbridge
597  {
599  }
600  else
602  }
603 
604  else if(!AutoSigsFlag && ConsecSignalsRoute)
605  {
606  if(SpeedTag == 64)
607  return RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers
608 
609  if(SpeedTag == 65)
611 
612  if(SpeedTag == 66)
614 
615  if(SpeedTag == 67)
617 
618  if(SpeedTag == 80)
619  return RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations
620 
621  if(SpeedTag == 81)
623 
624  if(SpeedTag == 82)
626 
627  if(SpeedTag == 83)
629 
630  if(SpeedTag == 84)
632 
633  if(SpeedTag == 85)
635 
636  if(SpeedTag == 86)
638 
639  if(SpeedTag == 87)
641 
642  if(SpeedTag == 129)
643  return RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
644 
645  if(SpeedTag == 130)
647 
648  if(XLinkPos == -1) // not set, could be first element or last element = leading point
649  {
650  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
651  if(Link[2] != -1)
652  return 0; // i.e. complex element, don't display
653  else
654  {
655  if(!EntryExitNumber())
656  {
657  throw Exception("Error in EntryExitNumber 10");
658  }
659  else
661  }
662  }
663  if(EXNumber > 15) // underbridge
664  {
666  }
667  else
669  }
670 
671  else
672  {
673  if(SpeedTag == 64)
674  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
675 
676  if(SpeedTag == 65)
678 
679  if(SpeedTag == 66)
681 
682  if(SpeedTag == 67)
684 
685  if(SpeedTag == 80)
686  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
687 
688  if(SpeedTag == 81)
690 
691  if(SpeedTag == 82)
693 
694  if(SpeedTag == 83)
696 
697  if(SpeedTag == 84)
699 
700  if(SpeedTag == 85)
702 
703  if(SpeedTag == 86)
705 
706  if(SpeedTag == 87)
708 
709  if(SpeedTag == 129)
710  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
711 
712  if(SpeedTag == 130)
714 
715  if(XLinkPos == -1) // not set, could be first element or last element = leading point
716  {
717  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
718  if(Link[2] != -1)
719  return 0; // i.e. complex element, don't display
720  else
721  {
722  if(!EntryExitNumber())
723  {
724  throw Exception("Error in EntryExitNumber 11");
725  }
726  else
728  }
729  }
730  if(EXNumber > 15) // underbridge
731  {
733  }
734  else
736  }
737 }
738 
739 // ---------------------------------------------------------------------------
740 
742 /*
743  As above but for route flashing graphics. (Disused - now combined with above)
744 */
745 {
746  if(SpeedTag == 64)
747  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers
748 
749  if(SpeedTag == 65)
751 
752  if(SpeedTag == 66)
754 
755  if(SpeedTag == 67)
757 
758  if(SpeedTag == 80)
759  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations
760 
761  if(SpeedTag == 81)
763 
764  if(SpeedTag == 82)
766 
767  if(SpeedTag == 83)
769 
770  if(SpeedTag == 84)
772 
773  if(SpeedTag == 85)
775 
776  if(SpeedTag == 86)
778 
779  if(SpeedTag == 87)
781 
782  if(SpeedTag == 129)
783  return RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
784 
785  if(SpeedTag == 130)
787 
788  if(XLinkPos == -1) // not set, could be first element or last element = leading point
789  {
790 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
791  if(Link[2] != -1)
792  return 0; // i.e. complex element, don't display
793  else
794  {
795  if(!EntryExitNumber())
796  {
797  throw Exception("Error in EntryExitNumber 7");
798  }
799  else
801  }
802  }
803  if(EXNumber > 15) // underbridge
804  {
806  }
807  else
809 }
810 
811 // ---------------------------------------------------------------------------
812 
814 /*
815  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
816 */
817 {
818  if((ELink > 0) && (ELink < 10) && (ELink != 5))
820  else
821  {
822  throw Exception("Error in EntryExitNumber 8");
823  }
824 }
825 
826 // ---------------------------------------------------------------------------
827 
828 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute) const
829 /*
830  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
831 */
832 {
833  if((ELink > 0) && (ELink < 10) && (ELink != 5))
834  {
835  if(!AutoSigsFlag && !ConsecSignalsRoute)
837  else if(!AutoSigsFlag && ConsecSignalsRoute)
839  else
841  }
842  else
843  {
844  throw Exception("Error in EntryExitNumber 9");
845  }
846 }
847 
848 // ---------------------------------------------------------------------------
849 
851 /*
852  Set == operator when TrackVectorPosition, ELink & XLink all same
853 */
854 {
855  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
856  return true;
857  else
858  return false;
859 }
860 
861 // ---------------------------------------------------------------------------
862 
864 /*
865  Set != operator when any of TrackVectorPosition, ELink or XLink different
866 */
867 {
868  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
869  return false;
870  else
871  return true;
872 }
873 
874 // ---------------------------------------------------------------------------
875 // Track functions
876 // ---------------------------------------------------------------------------
877 
878 // ---------------------------------------------------------------------------
879 
880 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
881 {
882  ConsecSignals = false;
883  ReducedTimePenalty = false;
884  BarrierState = Up;
885  ChangeDuration = 0.0;
887  HLoc = 0;
888  VLoc = 0;
889  StartTime = TDateTime(0);
890 }
891 
892 // ---------------------------------------------------------------------------
893 
895 {
896 // CurrentSpeedButtonTag = 0; //not assigned yet
897 
898  HLocMin = 2000000000;
899  VLocMin = 2000000000;
900  HLocMax = -2000000000;
901  VLocMax = -2000000000;
902  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
903  CopyFlag = false; // only true for copying, so names aren't copied
904 
905  AnsiString NL = '\n';
906 
907  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
908  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
909  "blocked by a train, another route or a changing level crossing; " + NL + NL +
910  "or invalid - possibly due to a preferred direction mismatch or a missed signal in a green or blue route.";
911 
916 
917  int InternalLinkCheckArray[9][2] =
918  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
919 
920 /* array of valid link values for 'old' location and 'new' location, where
921  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
922 
923  for(int x = 0; x < 9; x++)
924  for(int y = 0; y < 2; y++)
925  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
926 
927 // Platform and default track element values
928  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
929 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
930  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
931  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
932  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
933  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
934  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
935  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
936  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
937  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
938 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
939 
940  int HVArray[10][2] =
941  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
942 
943  for(int x = 0; x < 10; x++)
944  for(int y = 0; y < 2; y++)
945  LinkHVArray[x][y] = HVArray[x][y];
946  TrackFinished = false;
947 // DistancesSet = false;
948 
949  TSigElement TempSigTable[40] = // original four aspect
950  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
951  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
952 
955 
958 
959  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
960  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
961 
962  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
963  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
964  {75, 4, RailGraphics->gl75}};
965 
966  for(int x = 0; x < 40; x++)
967  {
968  SigTable[x] = TempSigTable[x];
969  }
970 
971  TSigElement TempSigTableThreeAspect[40] =
972  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
973  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
974 
977 
978  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
979  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
980 
981  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
982  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
983 
984  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
985  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
986  {75, 4, RailGraphics->gl75}};
987 
988  for(int x = 0; x < 40; x++)
989  {
990  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
991  }
992 
993  TSigElement TempSigTableTwoAspect[40] =
994  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
995  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
996 
997  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
998  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
999 
1000  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1001  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1002 
1003  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1004  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1005 
1006  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1007  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1008  {75, 4, RailGraphics->gl75}};
1009 
1010  for(int x = 0; x < 40; x++)
1011  {
1012  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1013  }
1014 
1015  TSigElement TempSigTableGroundSignal[40] =
1019 
1023 
1027 
1031 
1032  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1035 
1036  for(int x = 0; x < 40; x++)
1037  {
1038  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1039  }
1040 
1041 /*
1042  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1043  a single location. These are as follows:-
1044  Directly Adjacent = up, down, left or right - NOT diagonal.
1045  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1046  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1047  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1048 
1049  //t 76
1050  //b 77
1051  //l 78
1052  //r 79
1053  //c 96
1054  //v fb 129
1055  //h fb 130
1056  //v underpass 145
1057  //h underpass 146
1058  //n 131
1059 */
1060 
1061  int Tag76[25][3] =
1062  {{-1, 0, 96}, // c top plat
1063  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1064  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1065  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1066  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1067  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1068  {0, 0, 129}, {0, -1, 145}, // v up
1069  {0, 0, 145}};
1070 
1071  for(int x = 0; x < 25; x++)
1072  for(int y = 0; y < 3; y++)
1073  Tag76Array[x][y] = Tag76[x][y];
1074 
1075  int Tag77[25][3] =
1076  {{-1, 0, 96}, // c bot plat
1077  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1078  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1079  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1080  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1081  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1082  {0, 0, 129}, {0, 1, 145}, // v up
1083  {0, 0, 145}};
1084 
1085  for(int x = 0; x < 25; x++)
1086  for(int y = 0; y < 3; y++)
1087  Tag77Array[x][y] = Tag77[x][y];
1088 
1089  int Tag78[25][3] =
1090  {{-1, 0, 96}, // c left plat
1091  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1092  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1093  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1094  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1095  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1096  {0, 0, 130}, {-1, 0, 146}, // h up
1097  {0, 0, 146}};
1098 
1099  for(int x = 0; x < 25; x++)
1100  for(int y = 0; y < 3; y++)
1101  Tag78Array[x][y] = Tag78[x][y];
1102 
1103  int Tag79[25][3] =
1104  {{-1, 0, 96}, // c right plat
1105  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1106  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1107  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1108  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1109  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1110  {0, 0, 130}, {1, 0, 146}, // h up
1111  {0, 0, 146}};
1112 
1113  for(int x = 0; x < 25; x++)
1114  for(int y = 0; y < 3; y++)
1115  Tag79Array[x][y] = Tag79[x][y];
1116 
1117  int Tag96[28][3] =
1118  {{-1, 0, 96}, // c //concourse
1119  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1120  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1121  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1122  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1123  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1124  {0, -1, 129}, {1, 0, 130}, // h fb
1125  {-1, 0, 130}, {0, 1, 145}, // v up
1126  {0, -1, 145}, {1, 0, 146}, // h up
1127  {-1, 0, 146}};
1128 
1129  for(int x = 0; x < 28; x++)
1130  for(int y = 0; y < 3; y++)
1131  Tag96Array[x][y] = Tag96[x][y];
1132 
1133  int Tag129[8][3] = // vert fb
1134  {{0, -1, 96}, // c
1135  {0, -1, 77}, // b
1136  {0, -1, 129}, // v fb
1137 
1138  {0, 1, 96}, // c
1139  {0, 1, 76}, // t
1140  {0, 1, 129}, // v fb
1141 
1142  {0, 0, 76}, // t
1143  {0, 0, 77}}; // b
1144 
1145  for(int x = 0; x < 8; x++)
1146  for(int y = 0; y < 3; y++)
1147  Tag129Array[x][y] = Tag129[x][y];
1148 
1149  int Tag145[8][3] = // vert up
1150  {{0, -1, 96}, // c
1151  {0, -1, 77}, // b
1152  {0, -1, 145}, // v fb
1153 
1154  {0, 1, 96}, // c
1155  {0, 1, 76}, // t
1156  {0, 1, 145}, // v fb
1157 
1158  {0, 0, 76}, // t
1159  {0, 0, 77}}; // b
1160 
1161  for(int x = 0; x < 8; x++)
1162  for(int y = 0; y < 3; y++)
1163  Tag145Array[x][y] = Tag145[x][y];
1164 
1165  int Tag130[8][3] = // hor fb
1166  {{-1, 0, 96}, // c
1167  {-1, 0, 79}, // r
1168  {-1, 0, 130}, // h fb
1169 
1170  {1, 0, 96}, // c
1171  {1, 0, 78}, // l
1172  {1, 0, 130}, // h fb
1173 
1174  {0, 0, 78}, // l
1175  {0, 0, 79}}; // r
1176 
1177  for(int x = 0; x < 8; x++)
1178  for(int y = 0; y < 3; y++)
1179  Tag130Array[x][y] = Tag130[x][y];
1180 
1181  int Tag146[8][3] = // hor up
1182  {{-1, 0, 96}, // c
1183  {-1, 0, 79}, // r
1184  {-1, 0, 146}, // h fb
1185 
1186  {1, 0, 96}, // c
1187  {1, 0, 78}, // l
1188  {1, 0, 146}, // h fb
1189 
1190  {0, 0, 78}, // l
1191  {0, 0, 79}}; // r
1192 
1193  for(int x = 0; x < 8; x++)
1194  for(int y = 0; y < 3; y++)
1195  Tag146Array[x][y] = Tag146[x][y];
1196 
1197  int Tag131[4][3] =
1198  {{-1, 0, 131}, // n
1199  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1200 
1201  for(int x = 0; x < 4; x++)
1202  for(int y = 0; y < 3; y++)
1203  Tag131Array[x][y] = Tag131[x][y];
1204 
1205  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1206  {0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1207  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1208  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1209  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1210  140, 144, 145, 146};
1211 
1212  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1213  {0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1214  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1215  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1216  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1217  141, 144, 145, 146};
1218 
1219  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1220  {0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1221  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1222  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1223  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1224  141, 144, 146, 145};
1225 
1226  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1227  {0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1228  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1229  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1230  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1231  140, 144, 146, 145};
1232 
1233  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1234  {
1235  FlipArray[x] = InternalFlipArray[x];
1236  MirrorArray[x] = InternalMirrorArray[x];
1237  RotRightArray[x] = InternalRotRightArray[x];
1238  RotLeftArray[x] = InternalRotLeftArray[x];
1239  }
1240 }
1241 
1242 // ---------------------------------------------------------------------------
1244 {
1245 // delete TrackVectorPtr;
1246 // delete FixedTrackArrayPtr;
1247  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1248 
1249  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1250  {
1251  delete UGMIt->second;
1252  UGMIt++;
1253  }
1254  delete GapFlashGreen;
1255  delete GapFlashRed;
1256  // all the rest are cleared by the relevant automatic destructors
1257 }
1258 
1259 // ---------------------------------------------------------------------------
1260 
1262 {
1263  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1264  {
1265 // loc 0 not used, set to bmSolidBgnd
1269 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1289 
1290  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1291  {
1292 // loc 0 not used, set to smSolidBgnd
1296 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1315  RailGraphics->smTransparent, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1316  };
1317 
1318 // track types
1319  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1320  {Erase, // 1 0
1321  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1322  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1323  Crossover, Crossover, // 2 15-16
1324  Unused, // 17 (was for text in earlier development) //1 17
1327  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1331  Platform, Platform, Platform, Platform, // 4 76-79
1334  Concourse, // 1 96
1337  Simple, Simple, Simple, Simple, // 4 125-128
1338  FootCrossing, FootCrossing, // 2 129-130
1339  NamedNonStationLocation, // 1 131
1340  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1341  Simple, Simple, Simple, Simple, // 4 140-143
1342  LevelCrossing, // 1 144
1343  FootCrossing, FootCrossing // 2 145 & 146
1344  };
1345 
1346 // links
1347  int Links[FirstUnusedSpeedTagNumber][4] =
1348  {{-1, -1, -1, -1}, // erase element
1349  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1350  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1351 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1352  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1353  {-1, -1, -1, -1}, // unused
1354  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1355  {2, 7, -1, -1}, // simple
1356  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8
1357  }, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1358 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1359 // (or right diverging if no straight)
1360  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1361  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6
1362  }, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1363  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1364  }, // buffers - position 0 = buffer
1365  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1
1366  }, // signals (need Config to determine signal end, see below)
1367  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1368  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1369  }, // continuation - position 0 = continuation
1370  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1
1371  }, // gapjump - position 0 = gap
1372  {-1, -1, -1, -1}, // Concourse
1373  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1374  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1375  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1376  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1377  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1378  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1379  {-1, -1, -1, -1}, // NamedNonStationLocation
1380  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1381 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1382  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1383  {-1, -1, -1, -1}, // level crossing
1384  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1385  };
1386 
1388  {{NotSet, NotSet, NotSet, NotSet}, // unused
1392  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1394  {NotSet, NotSet, NotSet, NotSet}, // unused
1398  {Connection, Connection, NotSet, NotSet}, // simple
1402  {Lead, Trail, Lead, Trail}, // points
1404  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1413  }, // signals (signal at exit end in forward direction)
1417  }, // continuation
1420  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1429  {Connection, Connection, NotSet, NotSet}, // Arrows
1431  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1433  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1435  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1436  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1437  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1438  };
1439 
1440  for(int x = 0; x < 17; x++)
1441  {
1442  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1443  }
1444  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1445 // 17 was the old text value so don't want any graphics (now disused)
1446  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1447  {
1448  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1449  }
1450 }
1451 
1452 // ---------------------------------------------------------------------------
1453 TGraphicElement::TGraphicElement(): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1454  ExistingGraphicLoaded(false), Width(16), Height(16)
1455 {
1456  OriginalGraphic = new Graphics::TBitmap;
1457  OriginalGraphic->PixelFormat = pf8bit;
1458  OriginalGraphic->Width = Width;
1459  OriginalGraphic->Height = Height;
1460  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1461 }
1462 
1463 // ---------------------------------------------------------------------------
1464 
1465 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn): OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1466  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1467 {
1468  OriginalGraphic = new Graphics::TBitmap;
1469  OriginalGraphic->PixelFormat = pf8bit;
1470  OriginalGraphic->Width = Width;
1471  OriginalGraphic->Height = Height;
1472  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1473 }
1474 
1475 // ---------------------------------------------------------------------------
1476 
1478 {
1479  delete OriginalGraphic;
1480 }
1481 
1482 // ---------------------------------------------------------------------------
1483 
1484 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1485 {
1486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1487  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1488  VPos = VPosIn;
1489  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1490 
1491  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1492  SourceRect.init(Left, Top, Left + Width, Top + Height);
1493  ScreenSourceSet = true;
1494  Utilities->CallLogPop(422);
1495 }
1496 
1497 // ---------------------------------------------------------------------------
1498 
1500 {
1501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1502  if(!OverlayLoaded)
1503  {
1504  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1505  }
1506  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1507  {
1508  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1509  }
1510  if(!ScreenSourceSet)
1511  {
1512  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1513  }
1514  if(ExistingGraphicLoaded) // can only call one of the load functions
1515  {
1516  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1517  }
1518  if(OverlayPlotted) // don't load from screen if overlay plotted
1519  {
1520  Utilities->CallLogPop(775);
1521  return;
1522  }
1523  TRect DestRect(0, 0, Width, Height);
1524 
1526  OriginalLoaded = true;
1527  ScreenGraphicLoaded = true;
1528  Utilities->CallLogPop(423);
1529 }
1530 
1531 // ---------------------------------------------------------------------------
1532 
1533 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1534 /*
1535  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1536 */
1537 {
1538  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1539  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1540  if(!OverlayLoaded)
1541  {
1542  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1543  }
1544  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1545  {
1546  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1547  }
1548  if(ScreenGraphicLoaded) // can only call one of the load functions
1549  {
1550  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1551  }
1552  Width = WidthIn;
1553  Height = HeightIn;
1554  OriginalGraphic->Width = Width;
1555  OriginalGraphic->Height = Height;
1556  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1557  VPos += VOffset;
1558  TRect DestRect(0, 0, Width, Height);
1559 
1560  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1561  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1562  OriginalLoaded = true;
1563  ExistingGraphicLoaded = true;
1564  Utilities->CallLogPop(424);
1565 }
1566 
1567 // ---------------------------------------------------------------------------
1568 
1569 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1570 {
1571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1572  OverlayGraphic = Overlay;
1573  OverlayLoaded = true;
1574  Utilities->CallLogPop(425);
1575 }
1576 
1577 // ---------------------------------------------------------------------------
1578 
1580 {
1581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1582  if(!OverlayLoaded)
1583  {
1584  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1585  }
1586  if(!OverlayPlotted)
1587  {
1588  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1589  Disp->Update();
1590  OverlayPlotted = true;
1591  }
1592  Utilities->CallLogPop(426);
1593 }
1594 
1595 // ---------------------------------------------------------------------------
1596 
1598 {
1599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1600  if(OverlayPlotted)
1601  {
1602  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1603  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1604  {
1605  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1606  }
1607  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1608  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1609  OverlayPlotted = false;
1610  }
1611  Utilities->CallLogPop(427);
1612 }
1613 
1614 // ---------------------------------------------------------------------------
1615 
1617 {
1618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1619  bool TrackPresent = false;
1620 
1621  if(InactiveTrackVector.size() != 0)
1622  {
1623  Utilities->CallLogPop(1333);
1624  return false;
1625  }
1626  else if(TrackVector.size() == 0)
1627  {
1628  Utilities->CallLogPop(1334);
1629  return true;
1630  }
1631  else
1632  {
1633  for(unsigned int x = 0; x < TrackVector.size(); x++)
1634  {
1635  if((TrackVector.at(x).SpeedTag != 0))
1636  TrackPresent = true;
1637  }
1638  }
1639  Utilities->CallLogPop(1335);
1640  return !TrackPresent;
1641 }
1642 
1643 // ---------------------------------------------------------------------------
1644 
1645 bool TTrack::NoActiveTrack(int Caller)
1646 {
1647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1648  bool TrackPresent = false;
1649 
1650  if(TrackVector.size() == 0)
1651  {
1652  Utilities->CallLogPop(1582);
1653  return true;
1654  }
1655  else
1656  {
1657  for(unsigned int x = 0; x < TrackVector.size(); x++)
1658  {
1659  if((TrackVector.at(x).SpeedTag != 0))
1660  TrackPresent = true;
1661  break;
1662  }
1663  }
1664  Utilities->CallLogPop(1583);
1665  return !TrackPresent;
1666 }
1667 
1668 // ---------------------------------------------------------------------------
1669 
1670 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1671 {
1672  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1673  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1674  TrackEraseSuccessfulFlag = false;
1675 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1676 // since have to match platforms as well as track
1677 // used to set TrackFinished to false if an element erased
1678 
1679  ErasedTrackVectorPosition = -1; // marker for no element erased
1680  AnsiString SName = "", ErrorString;
1682  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1683  TTrackMapIterator TrackMapPtr;
1684  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1685 
1686  if(TrackVector.size() != 0)
1687  {
1688  TrackMapKeyPair.first = HLocInput;
1689  TrackMapKeyPair.second = VLocInput;
1690  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1691  if(TrackMapPtr != TrackMap.end())
1692  {
1693  bool FoundFlag;
1694  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1695  if(FoundFlag) // should find it as it's in the map
1696  {
1697  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1698  {
1699  SName = TrackElementAt(1, VecPos).LocationName;
1700  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1701  if(ErrorString != "")
1702  {
1703  throw Exception(ErrorString + " for EraseTrackElement 1");
1704  }
1705  LocationNameMultiMap.erase(SNIt);
1706  }
1707 
1708  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1709  // ensure erase vector element before map element as iterator no longer valid after a map erase
1710  TrackMap.erase(TrackMapPtr);
1711  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1712  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1714  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1715  if(SName != "")
1716  {
1717  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1718  int HPos, VPos;
1719  if(TextHandler->FindText(1, SName, HPos, VPos))
1720  {
1721  if(TextHandler->TextErase(5, HPos, VPos, SName))
1722  {;
1723  } // condition not used
1724  }
1725  }
1726  ErasedTrackVectorPosition = VecPos;
1727  TrackEraseSuccessfulFlag = true;
1728  }
1729  }
1730  }
1731 
1732  if(InactiveTrackVector.size() != 0)
1733  {
1734  unsigned int VecPos;
1735  InactiveTrackMapKeyPair.first = HLocInput;
1736  InactiveTrackMapKeyPair.second = VLocInput;
1737  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
1738  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1739  {
1740  SName = "";
1741  VecPos = InactiveTrack2MultiMapIterator->second;
1742  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
1743  {
1744  SName = InactiveTrackElementAt(1, VecPos).LocationName;
1745  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1746  if(ErrorString != "")
1747  {
1748  throw Exception(ErrorString + " for EraseTrackElement 2A");
1749  }
1750  LocationNameMultiMap.erase(SNIt);
1751  }
1752  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1753  // ensure erase vector element before map element as iterator no longer valid after a map erase
1754  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1755  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
1756  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1758  TrackEraseSuccessfulFlag = true;
1759  if(SName != "")
1760  {
1761  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1762  int HPos, VPos;
1763  if(TextHandler->FindText(2, SName, HPos, VPos))
1764  {
1765  if(TextHandler->TextErase(6, HPos, VPos, SName))
1766  {;
1767  } // condition not used
1768  }
1769  }
1770  }
1771 
1772  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
1773  {
1774  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
1775  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
1776  {
1777  SName = "";
1778  VecPos = InactiveTrack2MultiMapIterator->second;
1779  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
1780  {
1781  SName = InactiveTrackElementAt(3, VecPos).LocationName;
1782  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
1783  if(ErrorString != "")
1784  {
1785  throw Exception(ErrorString + " for EraseTrackElement 2B");
1786  }
1787  LocationNameMultiMap.erase(SNIt);
1788  }
1789  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
1790  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
1791  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1793  if(SName != "")
1794  {
1795  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1796  int HPos, VPos;
1797  if(TextHandler->FindText(3, SName, HPos, VPos))
1798  {
1799  if(TextHandler->TextErase(7, HPos, VPos, SName))
1800  {;
1801  } // condition not used
1802  }
1803  }
1804  }
1805  }
1806  }
1807  if(TrackEraseSuccessfulFlag)
1808  {
1809  CalcHLocMinEtc(2);
1810  SetTrackFinished(false);
1811  }
1812  if(InternalChecks)
1813  {
1814  CheckMapAndTrack(1); // test
1815  CheckMapAndInactiveTrack(1); // test
1816  CheckLocationNameMultiMap(6); // test
1817  }
1818  Utilities->CallLogPop(428);
1819 }
1820 
1821 // ---------------------------------------------------------------------------
1822 
1823 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
1824  // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
1825  // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
1826  // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
1827 {
1828  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
1829  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1830  bool PlatAllowedFlag = false;
1831 
1832  TrackLinkingRequiredFlag = false;
1833 /*
1834  Not erase, that covered separately.
1835  First check if Current SpeedButton assigned, then check if a platform and only
1836  permit if an appropriate trackpiece already there & not a same platform there.
1837  - can't enter a platform without track first.
1838  Then for non-platforms, check if a track piece already present at location &
1839  reject if so.
1840 */
1841 
1842  TLocationNameMultiMapEntry LocationNameEntry;
1843 
1844  LocationNameEntry.first = "";
1845  if(CurrentTag == 0)
1846  {
1847  Utilities->CallLogPop(429);
1848  return; // not assigned yet
1849  }
1850 
1851  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
1852 
1853  TempTrackElement.HLoc = HLocInput;
1854  TempTrackElement.VLoc = VLocInput;
1855  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
1856 // new at version 0.6 - set signal aspect depending on build mode
1857 
1858  if(TempTrackElement.TrackType == SignalPost)
1859  {
1860  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
1861  // pasting a SignalPost can only have values 1 to 4
1862  {
1864  {
1865  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1866  }
1868  {
1869  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1870  }
1872  {
1873  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1874  }
1875  else
1876  {
1877  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1878  }
1879  }
1880  else if(Aspect == 1)
1881  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
1882  else if(Aspect == 2)
1883  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
1884  else if(Aspect == 3)
1885  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
1886  else
1887  TempTrackElement.SigAspect = TTrackElement::FourAspect;
1888  }
1889 
1890  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
1891  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
1892  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
1893  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
1894 
1895  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
1896  {
1898  NonStationOrLevelCrossingPresent = true;
1899  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
1900  NonStationOrLevelCrossingPresent = true;
1901  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
1902  PlatformPresent = true;
1903  // no need to check IMPair.second since if that exists it is because .first is a platform
1904  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
1905  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
1906  }
1907 
1908 // check platforms
1909  if(TempTrackElement.TrackType == Platform)
1910  {
1911  if(FoundFlag) // active track element already there
1912  {
1913  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
1914  {;
1915  }
1916  // same platform type already there so above keeps PlatAllowedFlag false
1917  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1918  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
1919  {
1920  PlatAllowedFlag = true;
1921  }
1922  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1923  {
1924  PlatAllowedFlag = true;
1925  }
1926  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1927  {
1928  PlatAllowedFlag = true;
1929  }
1930  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
1931  {
1932  PlatAllowedFlag = true;
1933  }
1934  if(PlatAllowedFlag)
1935  {
1936  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
1937  TrackPush(1, TempTrackElement);
1938  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1939  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1940  // Must be called AFTER TrackPush
1941  // No need to plot the element - Clearand ... called after this function called
1942  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
1943  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
1944 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1945 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
1946 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
1947  if(InternalChecks)
1948  {
1949  CheckMapAndInactiveTrack(5); // test
1950  CheckLocationNameMultiMap(4); // test
1951  }
1952  Utilities->CallLogPop(430);
1953  return;
1954  }
1955  } // if(FoundFlag)
1956  Utilities->CallLogPop(431);
1957  return;
1958  } // if platform
1959 
1960 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
1961  if(TempTrackElement.TrackType == NamedNonStationLocation)
1962  {
1963  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
1964  (!FoundFlag && !InactiveFoundFlag))
1965  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
1966  {
1967  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
1968  TrackPush(2, TempTrackElement);
1969  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
1970  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
1971  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
1972  {
1973 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
1974 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
1975 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
1976  }
1977  if(InternalChecks)
1978  {
1979  CheckMapAndInactiveTrack(11); // test
1980  CheckLocationNameMultiMap(12); // test
1981  }
1982  Utilities->CallLogPop(432);
1983  return;
1984  }
1985  else
1986  {
1987  Utilities->CallLogPop(433);
1988  return;
1989  }
1990  }
1991 
1992 // check if a level crossing - OK if placed on a plain straight track
1993  if(TempTrackElement.TrackType == LevelCrossing)
1994  {
1995  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
1996  {
1997  TrackPush(11, TempTrackElement);
1998  PlotRaisedLinkedLevelCrossingBarriers(0, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
1999 // no need for reference to LC element as can't be open
2000  TrackLinkingRequiredFlag = true;
2001  Utilities->CallLogPop(1907);
2002  return;
2003  }
2004  else
2005  {
2006  Utilities->CallLogPop(1906);
2007  return; // was a level crossing but can't place it for some reason
2008  }
2009  }
2010 
2011 // check if another element already there
2012  else if(FoundFlag || InactiveFoundFlag)
2013  {
2014  Utilities->CallLogPop(434);
2015  return; // something already there (active or inactive track)
2016  }
2017 
2018 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2019 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2020 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2021 // do this after pushed into vector so that can use EnterLocationName
2022 
2023  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2024  {
2025  TrackPush(3, TempTrackElement);
2026  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2027  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2028  }
2029  else if(TempTrackElement.TrackType == Points)
2030  {
2031  TrackPush(4, TempTrackElement);
2032  bool BothPointFillets = true;
2033  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2034  }
2035  else if(TempTrackElement.TrackType == SignalPost)
2036  {
2037  TrackPush(10, TempTrackElement);
2038  PlotSignal(12, TempTrackElement, Display);
2039  }
2040  else
2041  {
2042  TrackPush(5, TempTrackElement);
2043  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2044  }
2045  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2046  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2047  if(InternalChecks)
2048  {
2049  CheckMapAndTrack(2); // test
2050  CheckMapAndInactiveTrack(2); // test
2051  CheckLocationNameMultiMap(5); // test
2052  }
2053  Utilities->CallLogPop(2062);
2054 }
2055 
2056 // ---------------------------------------------------------------------------
2057 
2058 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2059  bool InternalChecks)
2060  // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2061  // NB experimental: - need to change all caller numbers & check thoroughly if release
2062  // as is if single elements have location or platform names then have message that names fail to align when mouse over
2063  // need to deal with this if release - it's because ActiveTrackElementName is cleared in the new function, if not a single element
2064  // then set when call SearchForAndUpdateLocationName. Maybe instead of clearing can set to the InactiveTrackElementName at the same location?
2065 {
2066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2067  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2068  bool PlatAllowedFlag = false;
2069 
2070  TrackLinkingRequiredFlag = false;
2071 /*
2072  Not erase, that covered separately.
2073  First check if Current SpeedButton assigned, then check if a platform and only
2074  permit if an appropriate trackpiece already there & not a same platform there.
2075  - can't enter a platform without track first.
2076  Then for non-platforms, check if a track piece already present at location &
2077  reject if so.
2078 */
2079 
2080  TLocationNameMultiMapEntry LocationNameEntry;
2081 
2082  LocationNameEntry.first = "";
2083  if(TempTrackElement.SpeedTag == 0)
2084  {
2085  Utilities->CallLogPop(2063);
2086  return; // not assigned yet
2087  }
2088 
2089  TempTrackElement.HLoc = HLocInput;
2090  TempTrackElement.VLoc = VLocInput;
2091  for(int x = 0; x < 4; x++) // unset any gaps
2092  {
2093  if(TempTrackElement.Config[x] == Gap)
2094  TempTrackElement.ConnLinkPos[x] = -1;
2095  TempTrackElement.Conn[x] = -1;
2096  }
2097  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2098 // new at version 0.6 - set signal aspect depending on build mode
2099  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2100  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2101 
2102  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2103  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2104  // for the active track element because these aren't set
2105  // if don't do this then get a mismatch error during map checks later
2106 
2107  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2108 
2109  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2110  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2111 
2112  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2113  {
2114  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2115  NonStationOrLevelCrossingPresent = true;
2116  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2117  NonStationOrLevelCrossingPresent = true;
2118  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2119  PlatformPresent = true;
2120  // no need to check IMPair.second since if that exists it is because .first is a platform
2121  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2122  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2123  }
2124 
2125 // check platforms
2126  if(TempTrackElement.TrackType == Platform)
2127  {
2128  if(FoundFlag) // active track element already there
2129  {
2130  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2131  {;
2132  }
2133  // same platform type already there so above keeps PlatAllowedFlag false
2134  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2135  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2136  {
2137  PlatAllowedFlag = true;
2138  }
2139  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2140  {
2141  PlatAllowedFlag = true;
2142  }
2143  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2144  {
2145  PlatAllowedFlag = true;
2146  }
2147  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2148  {
2149  PlatAllowedFlag = true;
2150  }
2151  if(PlatAllowedFlag)
2152  {
2153  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2154  TrackPush(12, TempTrackElement);
2155 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2156  {
2157  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2158  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2159  }
2160  // Must be called AFTER TrackPush
2161 // No need to plot the element - Clearand ... called after this function called
2162  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2163  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2164 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2165 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2166 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2167  if(InternalChecks)
2168  {
2169  CheckMapAndInactiveTrack(12); // test
2170  CheckLocationNameMultiMap(20); // test
2171  }
2172  Utilities->CallLogPop(2064);
2173  return;
2174  }
2175  } // if(FoundFlag)
2176  Utilities->CallLogPop(2065);
2177  return;
2178  } // if platform
2179 
2180 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2181  if(TempTrackElement.TrackType == NamedNonStationLocation)
2182  {
2183  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2184  (!FoundFlag && !InactiveFoundFlag))
2185  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2186  {
2187  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2188  TrackPush(13, TempTrackElement);
2189 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2190  {
2191  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2192  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2193  }
2194  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2195  {
2196 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2197 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2198 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2199  }
2200  if(InternalChecks)
2201  {
2202  CheckMapAndInactiveTrack(13); // test
2203  CheckLocationNameMultiMap(21); // test
2204  }
2205  Utilities->CallLogPop(2066);
2206  return;
2207  }
2208  else
2209  {
2210  Utilities->CallLogPop(2067);
2211  return;
2212  }
2213  }
2214 
2215 // check if a level crossing - OK if placed on a plain straight track
2216  if(TempTrackElement.TrackType == LevelCrossing)
2217  {
2218  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2219  {
2220  TrackPush(14, TempTrackElement);
2221  PlotRaisedLinkedLevelCrossingBarriers(3, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2222 // no need for reference to LC element as can't be open
2223  TrackLinkingRequiredFlag = true;
2224  Utilities->CallLogPop(2068);
2225  return;
2226  }
2227  else
2228  {
2229  Utilities->CallLogPop(2069);
2230  return; // was a level crossing but can't place it for some reason
2231  }
2232  }
2233 
2234 // check if another element already there
2235  else if(FoundFlag || InactiveFoundFlag)
2236  {
2237  Utilities->CallLogPop(2070);
2238  return; // something already there (active or inactive track)
2239  }
2240 
2241 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2242 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2243 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2244 // do this after pushed into vector so that can use EnterLocationName
2245 
2246  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2247  {
2248  TrackPush(15, TempTrackElement);
2249  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2250  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2251  }
2252  else if(TempTrackElement.TrackType == Points)
2253  {
2254  TrackPush(16, TempTrackElement);
2255  bool BothPointFillets = true;
2256  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2257  }
2258  else if(TempTrackElement.TrackType == SignalPost)
2259  {
2260  TrackPush(17, TempTrackElement);
2261  PlotSignal(14, TempTrackElement, Display);
2262  }
2263  else
2264  {
2265  TrackPush(18, TempTrackElement);
2266  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2267  }
2268  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2269  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2270  if(InternalChecks)
2271  {
2272  CheckMapAndTrack(12); // test
2273  CheckMapAndInactiveTrack(14); // test
2274  CheckLocationNameMultiMap(22); // test
2275  }
2276  Utilities->CallLogPop(2071);
2277 }
2278 
2279 // ---------------------------------------------------------------------------
2280 
2281 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2282  // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2283  // return bool = true for success
2284  // LocError = true for location error & HLoc & VLoc to be inverted
2285 {
2286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2287  LocError = false;
2288  SetTrackFinished(false);
2289  if(TrackVector.size() == 0)
2290  {
2291  Utilities->CallLogPop(437);
2292  return false;
2293  }
2294  if(GapsUnset(7))
2295  {
2296  if(GiveMessages)
2297  ShowMessage("Gaps must be set before track can be validated");
2298  Utilities->CallLogPop(1135);
2299  return false;
2300  }
2301 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2302 // returns true for any unset gaps
2304  {
2305  // can keep this exception as protected by the GapsUnset call above
2306  throw Exception("Error, gaps unset when TryToConnectTrack called");
2307  }
2309  CheckGapMap(1); // test
2310 // Gap connections now securely defined
2311 
2312  CheckMapAndTrack(8); // test
2313 
2314 // Perform a pre-check prior to TrackMap being compiled
2315  if(GiveMessages)
2316  {
2317  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2318  {
2319  Utilities->CallLogPop(439);
2320  return false;
2321  }
2322  }
2323  else
2324  {
2325  if(!LinkTrackNoMessages(1, false))
2326  {
2327  Utilities->CallLogPop(1131);
2328  return false;
2329  }
2330  }
2331 
2332 // here if pre-check successful
2333  if(!RepositionAndMapTrack(0))
2334  {
2335  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2336  Utilities->CallLogPop(1138);
2337  return false;
2338  }
2339 // now perform the final assembly - FinalCall = true
2340  if(GiveMessages)
2341  {
2342  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2343  {
2344  Utilities->CallLogPop(1116);
2345  return false;
2346  }
2347  }
2348  else
2349  {
2350  if(!LinkTrackNoMessages(2, true))
2351  {
2352  Utilities->CallLogPop(1132);
2353  return false;
2354  }
2355  }
2356 
2357 // success
2358 
2359  PopulateLCVector(0);
2360  CheckGapMap(2); // test
2361  CheckMapAndTrack(3); // test
2362  CheckMapAndInactiveTrack(3); // test
2363  CheckLocationNameMultiMap(9); // test
2364  SetTrackFinished(true);
2365 
2366 // Build ContinuationNameMap
2367  std::pair<AnsiString, char>TempMapPair;
2368 
2369  ContinuationNameMap.clear();
2370  for(int x = 0; x < Track->TrackVectorSize(); x++)
2371  {
2372  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
2373  {
2374  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
2375  TempMapPair.second = 'x'; // unused
2376  ContinuationNameMap.insert(TempMapPair);
2377  }
2378  }
2379  Utilities->CallLogPop(440);
2380  return true;
2381 }
2382 
2383 // ---------------------------------------------------------------------------
2384 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2385  // unused - too time-consuming - double brute force search
2386 {
2387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2388  int NewHLoc, NewVLoc;
2389  bool ConnectionFoundFlag, LinkFoundFlag;
2390 
2391  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2392  {
2393  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2394  {
2395  if(TrackVector.at(x).Link[y] <= 0)
2396  continue; // no link
2397  if(TrackVector.at(x).Config[y] == End)
2398  continue; // buffer or continuation
2399  if(TrackVector.at(x).Config[y] == Gap)
2400  continue; // gap jump
2401  // get required H & V for track element joining link 'y'
2402  NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
2403  NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
2404  // find track element if present
2405  ConnectionFoundFlag = false;
2406  for(unsigned int z = 0; z < TrackVector.size(); z++)
2407  {
2408 // if(TrackElementAt(5, z).TrackType == Platform)
2409 // continue; //skip platforms
2410  if((TrackVector.at(z).HLoc == NewHLoc) && (TrackVector.at(z).VLoc == NewVLoc))
2411  {
2412  ConnectionFoundFlag = true;
2413  // find connecting link in the newly found track element if there is one
2414  LinkFoundFlag = false;
2415  for(unsigned int a = 0; a < 4; a++)
2416  {
2417  if(TrackVector.at(z).Link[a] == (10 - TrackVector.at(x).Link[y]))
2418  {
2419  LinkFoundFlag = true;
2420  }
2421  }
2422  // if there isn't a corresponding link set the invert values for the offending element
2423  if(!LinkFoundFlag)
2424  {
2425  HLoc = TrackVector.at(x).HLoc;
2426  VLoc = TrackVector.at(x).VLoc;
2427  Utilities->CallLogPop(441);
2428  return true;
2429  }
2430  break; // success, so break out of 'z' loop
2431  } // if((TrackVector.at(z).HLoc== NewHLoc) &&....
2432  } // for z...
2433  // if there isn't a connection set the invert values for the offending element
2434  if(!ConnectionFoundFlag)
2435  {
2436  HLoc = TrackVector.at(x).HLoc;
2437  VLoc = TrackVector.at(x).VLoc;
2438  Utilities->CallLogPop(442);
2439  return true;
2440  }
2441  } // for y....
2442  } // for x...
2443  Utilities->CallLogPop(443);
2444  return false; // all OK
2445 }
2446 
2447 // ---------------------------------------------------------------------------
2448 
2449 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2450 {
2451  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2452  TrackElement.LogTrack(0));
2453  bool FoundFlag;
2454 
2455  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2456  if(FoundFlag)
2457  TrackElement = TrackVector.at(Position);
2458  Utilities->CallLogPop(444);
2459  return FoundFlag;
2460 }
2461 
2462 // ---------------------------------------------------------------------------
2463 
2465 {
2466  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2467  if(NextTrackElementPtr >= TrackVector.end())
2468  {
2469  Utilities->CallLogPop(1336);
2470  return false;
2471  }
2472  Next = *NextTrackElementPtr;
2474  Utilities->CallLogPop(1337);
2475  return true;
2476 }
2477 
2478 // ---------------------------------------------------------------------------
2479 
2481 {
2482  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2484  {
2485  Utilities->CallLogPop(1338);
2486  return false;
2487  }
2488  Next = *NextTrackElementPtr;
2490  Utilities->CallLogPop(1339);
2491  return true;
2492 }
2493 
2494 // ---------------------------------------------------------------------------
2495 
2496 int TTrack::NumberOfGaps(int Caller)
2497 
2498 {
2499  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2500  int Count = 0;
2501 
2502  if(TrackVector.size() == 0)
2503  {
2504  Utilities->CallLogPop(1340);
2505  return 0;
2506  }
2507  for(unsigned int x = 0; x < TrackVector.size(); x++)
2508  {
2509  if(TrackVector.at(x).TrackType == GapJump)
2510  Count++;
2511  }
2512  Utilities->CallLogPop(1341);
2513  return Count;
2514 }
2515 
2516 // ---------------------------------------------------------------------------
2518  // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2519  // returns true for any unset gaps
2520 {
2521  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2522  bool UnsetGaps = false;
2523 
2524  if(TrackVector.size() == 0)
2525  {
2526  Utilities->CallLogPop(445);
2527  return false;
2528  }
2529  for(unsigned int x = 0; x < TrackVector.size(); x++)
2530  {
2531  if(TrackVector.at(x).TrackType != GapJump)
2532  {
2533  for(unsigned int y = 0; y < 4; y++)
2534  {
2535  TrackVector.at(x).Conn[y] = -1;
2536  TrackVector.at(x).ConnLinkPos[y] = -1;
2537  }
2538  }
2539  else // GapJump
2540  {
2541 // int tempint = TrackVector.at(x).Conn[0);
2542 
2543  if(TrackVector.at(x).Conn[0] == -1) // unset if -1
2544  {
2545  for(unsigned int y = 0; y < 4; y++)
2546  {
2547  TrackVector.at(x).Conn[y] = -1;
2548  TrackVector.at(x).ConnLinkPos[y] = -1;
2549  }
2550  UnsetGaps = true;
2551  continue; // to next 'x'
2552  }
2553  else // set, but may not have matching element, or that element may not be set
2554  {
2555  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2556  {
2557  TrackVector.at(x).Conn[y] = -1;
2558  TrackVector.at(x).ConnLinkPos[y] = -1;
2559  }
2560 
2561  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
2562  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2563  {
2564  for(unsigned int y = 0; y < 4; y++)
2565  {
2566  TrackVector.at(x).Conn[y] = -1;
2567  TrackVector.at(x).ConnLinkPos[y] = -1;
2568  }
2569  UnsetGaps = true;
2570  continue; // to next 'x'
2571  }
2572 // here if gap connection is itself a GapJump
2573  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
2574  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2575  // if not clear Conns & CLks & reset Lk[0]
2576  {
2577  for(unsigned int y = 0; y < 4; y++)
2578  {
2579  TrackVector.at(x).Conn[y] = -1;
2580  TrackVector.at(x).ConnLinkPos[y] = -1;
2581  }
2582  UnsetGaps = true;
2583  continue; // to next 'x'
2584  }
2585 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2586 // hence no more action needed on these Conns & CLks
2587  }
2588  } // else //gap jump
2589  } // for x...
2590  Utilities->CallLogPop(446);
2591  return UnsetGaps;
2592 }
2593 
2594 // ---------------------------------------------------------------------------
2595 
2596 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2597 {
2598 // VecFile already open and its pointer at right place on calling
2599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2600  int TempInt;
2601 
2602  TrackClear(1);
2603 // load track elements
2604  int NumberOfActiveElements = 0;
2605 
2606  GraphicsFollow = false;
2607  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2608  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2609 
2610  if(MarkerString[MarkerString.Length()] == '1')
2611  {
2612  GraphicsFollow = true;
2613  }
2614  for(int x = 0; x < NumberOfActiveElements; x++)
2615  {
2616  VecFile >> TempInt; // TrackVectorNumber, not used
2617  VecFile >> TempInt; // SpeedTag
2618  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2619  VecFile >> TempInt;
2620  TrackElement.HLoc = TempInt;
2621  VecFile >> TempInt;
2622  TrackElement.VLoc = TempInt;
2623  if(TrackElement.TrackType == GapJump)
2624  {
2625  VecFile >> TempInt;
2626  TrackElement.ConnLinkPos[0] = TempInt;
2627  VecFile >> TempInt;
2628  TrackElement.Conn[0] = TempInt;
2629  }
2630  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2631  {
2632  VecFile >> TempInt;
2633  TrackElement.Attribute = TempInt;
2634  }
2635  if(TrackElement.TrackType == SignalPost)
2636  {
2637  VecFile >> TempInt;
2638  if(TempInt == 0)
2639  TrackElement.CallingOnSet = false;
2640  else
2641  TrackElement.CallingOnSet = true;
2642  }
2643  VecFile >> TempInt;
2644  TrackElement.Length01 = TempInt;
2645  VecFile >> TempInt;
2646  TrackElement.Length23 = TempInt;
2647  VecFile >> TempInt;
2648  if((TempInt != -1) && (TempInt < 10))
2649  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2650  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2651  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2652  TrackElement.SpeedLimit01 = TempInt;
2653  VecFile >> TempInt;
2654  if((TempInt != -1) && (TempInt < 10))
2655  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2656  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2657  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2658  TrackElement.SpeedLimit23 = TempInt;
2659 
2660  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2661  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
2662  SetElementID(0, TrackElement);
2663  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
2664 // new for v0.6
2665  if(TrackElement.TrackType == SignalPost)
2666  {
2667  if(Marker[1] == '3')
2668  {
2669  TrackElement.SigAspect = TTrackElement::ThreeAspect;
2670  }
2671  else if(Marker[1] == '2')
2672  {
2673  TrackElement.SigAspect = TTrackElement::TwoAspect;
2674  }
2675  else if(Marker[1] == 'G')
2676  {
2677  TrackElement.SigAspect = TTrackElement::GroundSignal;
2678  }
2679  else
2680  {
2681  TrackElement.SigAspect = TTrackElement::FourAspect;
2682  }
2683  }
2684  if(TrackElement.SpeedTag != 0)
2685  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
2686  }
2687  int NumberOfInactiveElements = 0;
2688 
2689  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
2690  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
2691  for(int x = 0; x < NumberOfInactiveElements; x++)
2692  {
2693  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
2694  VecFile >> TempInt; // SpeedTag
2695  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2696  VecFile >> TempInt;
2697  TrackElement.HLoc = TempInt;
2698  VecFile >> TempInt;
2699  TrackElement.VLoc = TempInt;
2700  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2701  SetElementID(3, TrackElement);
2702  TrackPush(9, TrackElement);
2703  Utilities->LoadFileString(VecFile); // marker
2704  }
2705  bool LocError = false; // needed for TryToConnectTrack but not used
2706  int H = -1, V = -1; // needed for TryToConnectTrack but not used
2707 
2708  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
2709  {
2710  SetTrackFinished(true);
2711  }
2712  else
2713  {
2714  SetTrackFinished(false);
2715  }
2716 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
2717 // CheckMapAndInactiveTrack(8);
2718 // CheckLocationNameMultiMap(10);
2719  Utilities->CallLogPop(448);
2720 }
2721 
2722 // ---------------------------------------------------------------------------
2723 
2724 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
2725 {
2726 // VecFile already open and its pointer at right place on calling
2727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
2728 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
2729 // & load into UserGraphicItem then store in UserGraphicVector
2730  UserGraphicVector.clear();
2731  TUserGraphicItem UGI;
2732  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
2733 
2734  for(int x = 0; x < NumberOfGraphics; x++)
2735  {
2736  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
2737  UGI.HPos = Utilities->LoadFileInt(VecFile);
2738  UGI.VPos = Utilities->LoadFileInt(VecFile);
2739  UGI.Width = 0; // provisional value
2740  UGI.Height = 0; // provisional value
2741  UGI.UserGraphic = NULL; // provisional value
2742  UserGraphicVector.push_back(UGI);
2743  }
2744 // now load the map & set Width, Height & TPicture*
2745  bool FileError = false;
2746 
2747  for(int x = 0; x < NumberOfGraphics; x++)
2748  {
2749  if(FileError)
2750  {
2751  break; // otherwise keeps going round the loop
2752  }
2753  UGI = UserGraphicVectorAt(0, x);
2754  if(UserGraphicMap.empty()) // will be when x == 0 but not after
2755  {
2756  try
2757  {
2758 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
2759  UGME.first = UGI.FileName;
2760  UGME.second = new TPicture;
2761  UGME.second->LoadFromFile(UGME.first); // errors caught below
2762  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2763  {
2764  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
2765  }
2766  UGI.UserGraphic = UGME.second;
2767  UGI.Width = UGI.UserGraphic->Width;
2768  UGI.Height = UGI.UserGraphic->Height;
2769  UserGraphicVectorAt(1, x) = UGI;
2770  }
2771  catch(const EInvalidGraphic &e)
2772  {
2773  //message already sent in CheckUserGraphics
2774  FileError = true;
2775  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2776  if(!UserGraphicMap.empty())
2777  {
2778  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2779  {
2780  delete UGMIt->second;
2781  }
2782  UserGraphicMap.clear();
2783  }
2784  }
2785  catch(const Exception &e)
2786  {
2787  //message already sent in CheckUserGraphics
2788  FileError = true;
2789  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2790  if(!UserGraphicMap.empty())
2791  {
2792  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2793  {
2794  delete UGMIt->second;
2795  }
2796  UserGraphicMap.clear();
2797  }
2798  }
2799  }
2800  else
2801  {
2802  bool FoundInMap = false;
2803  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2804  {
2805  if(UGI.FileName == UGMIt->first) // already exists in map
2806  {
2807  UGI.UserGraphic = UGMIt->second;
2808  UGI.Width = UGI.UserGraphic->Width;
2809  UGI.Height = UGI.UserGraphic->Height;
2810  UserGraphicVectorAt(2, x) = UGI;
2811  FoundInMap = true;
2812  break;
2813  }
2814  }
2815  if(!FoundInMap)
2816  {
2817  try
2818  {
2820  UGME.first = UGI.FileName;
2821  UGME.second = new TPicture;
2822  UGME.second->LoadFromFile(UGME.first); // errors caught below
2823  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
2824  {
2825  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
2826  }
2827  UGI.UserGraphic = UGME.second;
2828  UGI.Width = UGI.UserGraphic->Width;
2829  UGI.Height = UGI.UserGraphic->Height;
2830  UserGraphicVectorAt(3, x) = UGI;
2831  }
2832  catch(const EInvalidGraphic &e)
2833  {
2834  //message already sent in CheckUserGraphics
2835  FileError = true;
2836  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2837  if(!UserGraphicMap.empty())
2838  {
2839  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2840  {
2841  delete UGMIt->second;
2842  }
2843  UserGraphicMap.clear();
2844  }
2845  }
2846  catch(const Exception &e)
2847  {
2848  //message already sent in CheckUserGraphics
2849  FileError = true;
2850  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
2851  if(!UserGraphicMap.empty())
2852  {
2853  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
2854  {
2855  delete UGMIt->second;
2856  }
2857  UserGraphicMap.clear();
2858  }
2859  }
2860  }
2861  }
2862  }
2863  Utilities->CallLogPop(2167);
2864 }
2865 
2866 // ---------------------------------------------------------------------------
2867 
2868 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
2869 {
2870 // VecFile already open and its pointer at right place on calling
2871 // if GraphicsFollow true, then save Marker as **Active elements**1
2872 // save trackfinished flag
2873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
2874  TTrackElement TrackElement, InactiveTrackElement;
2875 
2876 // save track elements
2877  Utilities->SaveFileInt(VecFile, TrackVector.size());
2878  if(GraphicsFollow)
2879  {
2880  VecFile << "**Active elements**1" << '\0' << '\n';
2881  }
2882  else
2883  {
2884  VecFile << "**Active elements**" << '\0' << '\n';
2885  }
2886  for(unsigned int x = 0; x < (TrackVector.size()); x++)
2887  {
2888  TrackElement = TrackVector.at(x);
2889  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
2890  VecFile << TrackElement.SpeedTag << '\n';
2891  VecFile << TrackElement.HLoc << '\n';
2892  VecFile << TrackElement.VLoc << '\n';
2893  if(TrackElement.TrackType == GapJump)
2894  {
2895  VecFile << TrackElement.ConnLinkPos[0] << '\n';
2896  VecFile << TrackElement.Conn[0] << '\n';
2897  }
2898  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2899  {
2900  VecFile << TrackElement.Attribute << '\n';
2901  }
2902  if(TrackElement.TrackType == SignalPost)
2903  {
2904  if(TrackElement.CallingOnSet)
2905  VecFile << int(1) << '\n';
2906  else
2907  VecFile << int(0) << '\n';
2908  }
2909  VecFile << TrackElement.Length01 << '\n';
2910  VecFile << TrackElement.Length23 << '\n';
2911  VecFile << TrackElement.SpeedLimit01 << '\n';
2912  VecFile << TrackElement.SpeedLimit23 << '\n';
2913  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2914  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2915 // new for v0.6
2916  if(TrackElement.TrackType == SignalPost)
2917  {
2918  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
2919  {
2920  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2921  }
2922  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
2923  {
2924  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2925  }
2926  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
2927  {
2928  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2929  }
2930  else // 4 aspect
2931  {
2932  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2933  }
2934  }
2935  else
2936  {
2937  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2938  }
2939  }
2940 
2941  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
2942  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
2943  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
2944  {
2945  InactiveTrackElement = InactiveTrackVector.at(x);
2946  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
2947  VecFile << InactiveTrackElement.SpeedTag << '\n';
2948  VecFile << InactiveTrackElement.HLoc << '\n';
2949  VecFile << InactiveTrackElement.VLoc << '\n';
2950  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2951  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
2952  }
2953  Utilities->CallLogPop(449);
2954 }
2955 
2956 // ---------------------------------------------------------------------------
2957 
2958 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
2959 {
2960 // VecFile already open and its pointer at right place on calling
2961 // check trackfinished flag
2962 // inactive elements follow immediately after active elements, no need to check for a marker between them
2963  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
2964  int TempInt;
2965 
2966  GraphicsFollow = false;
2967  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2968  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
2969  {
2970  Utilities->CallLogPop(1513);
2971  return false;
2972  }
2973 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
2974  AnsiString MarkerString;
2975 
2976  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
2977  {
2978  Utilities->CallLogPop(1758);
2979  return false;
2980  }
2981  if(MarkerString[MarkerString.Length()] == '1')
2982  {
2983  GraphicsFollow = true;
2984  }
2985  for(int x = 0; x < NumberOfActiveElements; x++)
2986  {
2987  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
2988  {
2989  Utilities->CallLogPop(1759);
2990  return false;
2991  }
2992  VecFile >> TempInt;
2993  int SpeedTag = TempInt;
2994  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
2995  {
2996  Utilities->CallLogPop(1514);
2997  return false;
2998  }
2999  VecFile >> TempInt;
3000  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3001  {
3002  Utilities->CallLogPop(1495);
3003  return false;
3004  }
3005  VecFile >> TempInt;
3006  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3007  {
3008  Utilities->CallLogPop(1497);
3009  return false;
3010  }
3011  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3012  {
3013  VecFile >> TempInt;
3014  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3015  {
3016  Utilities->CallLogPop(1499);
3017  return false;
3018  }
3019  VecFile >> TempInt;
3020  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3021  {
3022  Utilities->CallLogPop(1500);
3023  return false;
3024  }
3025  }
3026  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3027  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3028  {
3029  VecFile >> TempInt;
3030  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3031  {
3032  Utilities->CallLogPop(1502);
3033  return false;
3034  }
3035  }
3036  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3037  {
3038  VecFile >> TempInt;
3039  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3040  {
3041  Utilities->CallLogPop(1155);
3042  return false;
3043  }
3044  }
3045  VecFile >> TempInt;
3046  if((TempInt < -1) || (TempInt > 999999)) // Length01
3047  {
3048  Utilities->CallLogPop(1503);
3049  return false;
3050  }
3051  VecFile >> TempInt;
3052  if((TempInt < -1) || (TempInt > 999999)) // Length23
3053  {
3054  Utilities->CallLogPop(1504);
3055  return false;
3056  }
3057  VecFile >> TempInt;
3058  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3059  {
3060  Utilities->CallLogPop(1505);
3061  return false;
3062  }
3063  VecFile >> TempInt;
3064  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3065  {
3066  Utilities->CallLogPop(1506);
3067  return false;
3068  }
3069  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3070  {
3071  Utilities->CallLogPop(1142);
3072  return false; // LocationName
3073  }
3074  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3075  {
3076  Utilities->CallLogPop(1143);
3077  return false; // ActiveTrackElementName
3078  }
3079  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3080  {
3081  Utilities->CallLogPop(1787);
3082  return false; // marker
3083  }
3084  }
3085  int NumberOfInactiveElements = 0;
3086 
3087  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3088  if(NumberOfInactiveElements < 0) // No of active elements
3089  {
3090  Utilities->CallLogPop(1493);
3091  return false;
3092  }
3093  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3094  {
3095  Utilities->CallLogPop(1764);
3096  return false; // **Inactive elements** marker
3097  }
3098  for(int x = 0; x < NumberOfInactiveElements; x++)
3099  {
3100  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3101  {
3102  Utilities->CallLogPop(1765);
3103  return false;
3104  }
3105  VecFile >> TempInt;
3106  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3107  {
3108  Utilities->CallLogPop(1494);
3109  return false;
3110  }
3111  VecFile >> TempInt;
3112  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3113  {
3114  Utilities->CallLogPop(1496);
3115  return false;
3116  }
3117  VecFile >> TempInt;
3118  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3119  {
3120  Utilities->CallLogPop(1498);
3121  return false;
3122  }
3123  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3124  {
3125  Utilities->CallLogPop(1144);
3126  return false; // LocationName
3127  }
3128  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3129  {
3130  Utilities->CallLogPop(1788);
3131  return false; // marker
3132  }
3133  }
3134  Utilities->CallLogPop(1507);
3135  return true;
3136 }
3137 
3138 // ---------------------------------------------------------------------------
3139 
3140 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3141 {
3142  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3143  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3144 
3145  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3146  {
3147  Utilities->CallLogPop(2168);
3148  return false;
3149  }
3150  // filename in Graphics folder, then HPos, then VPos
3151  AnsiString FileName = "", TempStr = "";
3152 
3153  for(int x = 0; x < NumberOfGraphics; x++)
3154  {
3155  TPicture *TempPicture = new TPicture;
3156  try
3157  {
3158  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3159  {
3160  Utilities->CallLogPop(2169);
3161  delete TempPicture;
3162  return false;
3163  }
3164  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3165  delete TempPicture;
3166  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3167  {
3168  Utilities->CallLogPop(2170);
3169  return false;
3170  }
3171  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3172  {
3173  Utilities->CallLogPop(2171);
3174  return false;
3175  }
3176  }
3177  catch(const EInvalidGraphic &e)
3178  {
3179  //move file pointer to end of graphic section for later checks in session files
3180  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3181  Utilities->CheckAndReadFileString(VecFile, TempStr);//VPos
3182  for(int y = x + 1; y < NumberOfGraphics; y++)
3183  {
3184  Utilities->CheckAndReadFileString(VecFile, TempStr);//next FileName
3185  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3186  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3187  }
3188  ShowMessage(FileName +
3189  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3190  Utilities->CallLogPop(2172);
3191  delete TempPicture;
3192  return true; //for these file errors allow railway or session to be loaded, changed at v2.6.0
3193  }
3194  catch(const Exception &e)
3195  {
3196  //move file pointer to end of graphic section for later checks in session files
3197  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3198  Utilities->CheckAndReadFileString(VecFile, TempStr);//VPos
3199  for(int y = x + 1; y < NumberOfGraphics; y++)
3200  {
3201  Utilities->CheckAndReadFileString(VecFile, TempStr);//next FileName
3202  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3203  Utilities->CheckAndReadFileString(VecFile, TempStr);//next VPos
3204  }
3205  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3206  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3207  Utilities->CallLogPop(2173);
3208  delete TempPicture;
3209  return true; //for these file errors allow railway or session to be loaded, changed at v2.6.0
3210  }
3211  }
3212  Utilities->CallLogPop(2174);
3213  return true;
3214 }
3215 
3216 // ---------------------------------------------------------------------------
3217 
3218 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3219 {
3220  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3221  int VecSize = Track->BarriersDownVector.size();
3222 
3223  Utilities->SaveFileInt(OutFile, VecSize);
3224  for(int x = 0; x < VecSize; x++)
3225  {
3227  Utilities->SaveFileInt(OutFile, TALC.ConsecSignals); //changed to int from bool in v2.6.0
3228  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3229  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3230  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3231  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3232  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3233  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3234  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3235  }
3236  Utilities->CallLogPop(1963);
3237 }
3238 
3239 // ---------------------------------------------------------------------------
3240 
3241 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3242 {
3243  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3244  int VecSize = Track->ChangingLCVector.size();
3245 
3246  Utilities->SaveFileInt(OutFile, VecSize);
3247  for(int x = 0; x < VecSize; x++)
3248  {
3250  Utilities->SaveFileInt(OutFile, TALC.ConsecSignals); //changed to int from bool in v2.6.0
3251  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3252  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3253  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3254  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3255  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3256  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3257  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3258  }
3259  Utilities->CallLogPop(1980);
3260 }
3261 
3262 // ---------------------------------------------------------------------------
3263 
3264 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3265 {
3266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3267  int VecSize = Utilities->LoadFileInt(VecFile);
3268 
3269  for(int x = 0; x < VecSize; x++)
3270  {
3271  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow ConsecSignals == 2 for barriers manually lowered
3272  {
3273  Utilities->CallLogPop(1970);
3274  return false;
3275  }
3276  if(!Utilities->CheckFileBool(VecFile))
3277  {
3278  Utilities->CallLogPop(1971);
3279  return false;
3280  }
3281  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3282  {
3283  Utilities->CallLogPop(1972);
3284  return false;
3285  }
3286  if(!Utilities->CheckFileDouble(VecFile))
3287  {
3288  Utilities->CallLogPop(1973);
3289  return false;
3290  }
3291  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3292  {
3293  Utilities->CallLogPop(1974);
3294  return false;
3295  }
3296  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3297  {
3298  Utilities->CallLogPop(1975);
3299  return false;
3300  }
3301  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3302  {
3303  Utilities->CallLogPop(1976);
3304  return false;
3305  }
3306  if(!Utilities->CheckFileDouble(VecFile))
3307  {
3308  Utilities->CallLogPop(1977);
3309  return false;
3310  }
3311  }
3312  Utilities->CallLogPop(1978);
3313  return true;
3314 }
3315 
3316 // ---------------------------------------------------------------------------
3317 
3318 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3319 {
3320  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3321  int VecSize = Utilities->LoadFileInt(VecFile);
3322 
3323  for(int x = 0; x < VecSize; x++)
3324  {
3325  TActiveLevelCrossing TALC;
3326  TALC.ConsecSignals = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3327  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3328  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3329  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3330  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3331  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3332  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3333  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3334  BarriersDownVector.push_back(TALC);
3335  }
3336  Utilities->CallLogPop(1979);
3337 }
3338 
3339 // ---------------------------------------------------------------------------
3340 
3341 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3342 /*
3343  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3344  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3345  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3346 */
3347 {
3348  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3349  TTrackElement Next;
3350 
3351 // Disp->ClearDisplay();
3353  while(ReturnNextInactiveTrackElement(0, Next))
3354  {
3355  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3356  {
3357  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3358  {
3359  // only plot if on screen, to save time
3360  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3362  {
3363  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3364  }
3365  }
3366  }
3367  }
3368 
3369  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3370 
3371  NextTrackElementPtr = TrackVector.begin();
3372  while(ReturnNextTrackElement(0, Next))
3373  {
3374  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3375  {
3376  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3378  {
3379  if(Next.TrackType == Points)
3380  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3381  else if(Next.TrackType == SignalPost)
3382  PlotSignal(9, Next, Disp);
3383  else if(Next.TrackType == GapJump)
3384  PlotGap(0, Next, Disp);
3385  else
3386  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3387  }
3388  }
3389  }
3390 
3391  if(BothPointFilletsAndBasicLCs)
3392  {
3394  while(ReturnNextInactiveTrackElement(4, Next))
3395  {
3396  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3397  {
3398  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3399  {
3400  // only plot if on screen, to save time, & OK as plotting one by one here
3401  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3403  {
3404  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3405  {
3406  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3407  }
3408  else
3409  {
3410  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3411  }
3412  }
3413  }
3414  }
3415  }
3416  }
3417  Disp->Update();
3418  Utilities->CallLogPop(468);
3419 }
3420 
3421 // ---------------------------------------------------------------------------
3422 
3423 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3424 {
3425  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3426  if(UserGraphicVector.empty())
3427  {
3428  Utilities->CallLogPop(2175);
3429  return;
3430  }
3431  TUserGraphicItem UGI;
3432 
3433  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3434  {
3435  UGI = UserGraphicVectorAt(4, x);
3436  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3437  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3438  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3439  {
3440  Disp->PlotAndAddUserGraphic(0, UGI);
3441  }
3442  }
3443  Disp->Update();
3444  Utilities->CallLogPop(2176);
3445 }
3446 
3447 // ---------------------------------------------------------------------------
3448 
3449 void TTrack::WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3450 /*
3451  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3452 */
3453 {
3454  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackToImage");
3455 // need to change graphics back to black on white if have a dark background
3456  TColor OldTransparentColour = Utilities->clTransparent;
3457 
3459  {
3460  Utilities->clTransparent = TColor(0xFFFFFF); // white
3463  }
3464  TTrackElement Next;
3465 
3466  Bitmap->Canvas->CopyMode = cmSrcCopy;
3468  Graphics::TBitmap *GraphicOutput;
3469 
3470  while(ReturnNextInactiveTrackElement(2, Next))
3471  {
3472  GraphicOutput = Next.GraphicPtr;
3473  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3474  {
3475  if(Next.LocationName == "") // plot as named or unnamed (striped)
3476  { // default is not striped
3477  switch(Next.SpeedTag)
3478  {
3479  case 76: // t platform
3480  GraphicOutput = RailGraphics->gl76Striped;
3481  break;
3482 
3483  case 77: // h platform
3484  GraphicOutput = RailGraphics->bm77Striped;
3485  break;
3486 
3487  case 78: // v platform
3488  GraphicOutput = RailGraphics->bm78Striped;
3489  break;
3490 
3491  case 79: // r platform
3492  GraphicOutput = RailGraphics->gl79Striped;
3493  break;
3494 
3495  case 96: // concourse
3496  GraphicOutput = RailGraphics->ConcourseStriped;
3497  break;
3498 
3499  case 129: // v footbridge
3500  GraphicOutput = RailGraphics->gl129Striped;
3501  break;
3502 
3503  case 130: // h footbridge
3504  GraphicOutput = RailGraphics->gl130Striped;
3505  break;
3506 
3507  case 131: // non-station named loc
3508  GraphicOutput = RailGraphics->bmNameStriped;
3509  break;
3510 
3511  case 145: // v underpass
3512  GraphicOutput = RailGraphics->gl145Striped;
3513  break;
3514 
3515  case 146: // h underpass
3516  GraphicOutput = RailGraphics->gl146Striped;
3517  break;
3518 
3519  default:
3520  GraphicOutput = Next.GraphicPtr;
3521  break;
3522  }
3523  }
3524  if(Next.SpeedTag == 144) // level crossing
3525  {
3526  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3527  {
3528  GraphicOutput = RailGraphics->LCBothVer;
3529  }
3530  else
3531  {
3532  GraphicOutput = RailGraphics->LCBothHor;
3533  }
3534  }
3535  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3536  }
3537  }
3538 
3539  NextTrackElementPtr = TrackVector.begin();
3540  while(ReturnNextTrackElement(2, Next))
3541  {
3542  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3543  {
3544  if(Next.TrackType == Points) // plot both fillets
3545  {
3546  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3547  if(Next.SpeedTag < 28)
3548  {
3549  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3551  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3553  }
3554  else if(Next.SpeedTag < 132)
3555  {
3556  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3557  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3558  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3559  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3560  }
3561  else
3562  {
3563  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3564  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3565  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3566  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3567  }
3568  }
3569  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3570  {
3571  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3572  {
3573  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3574  }
3575  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3576  {
3577  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3578  }
3579  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3580  {
3581  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3582  }
3583  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3584  {
3585  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3586  }
3587  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3588  {
3589  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3590  }
3591  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3592  {
3593  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3594  }
3595  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3596  {
3597  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3598  }
3599  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3600  {
3601  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3602  }
3603  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3604  {
3605  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3606  }
3607  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3608  {
3609  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
3610  }
3611  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
3612  {
3613  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3614  }
3615  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
3616  {
3617  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
3618  }
3619  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
3620  {
3621  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3622  }
3623  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
3624  {
3625  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
3626  }
3627  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
3628  {
3629  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3630  }
3631  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
3632  {
3633  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
3634  }
3635  }
3636  // below added for version 0.6, only stop signals to be drawn
3637  else if(Next.TrackType == SignalPost)
3638  {
3639  for(int x = 0; x < 40; x++)
3640  {
3641  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
3642  {
3643  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3644  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3645  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3646  int HOffset = 0;
3647  if(Next.SpeedTag > 73)
3648  HOffset = 5;
3649  else if(Next.SpeedTag == 71)
3650  HOffset = 9;
3651  int VOffset = 0;
3652  if(Next.SpeedTag == 69)
3653  VOffset = 9;
3654  else if(Next.SpeedTag == 72)
3655  VOffset = 5;
3656  else if(Next.SpeedTag == 74)
3657  VOffset = 5;
3658  Graphics::TBitmap *GraphicPtr;
3659  if(Next.SpeedTag > 71)
3660  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3661  else if(Next.SpeedTag < 70)
3662  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3663  else
3664  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3665  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3666  // plot special signal platform if present
3667  Graphics::TBitmap* SignalPlatformGraphic;
3668  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
3669  {
3670  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3671  }
3672  // now plot signal (double yellow overwrites most of signal platform if present)
3673  // below amended for version 0.6
3675  {
3676  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3677  }
3678  else if(Next.SigAspect == TTrackElement::TwoAspect)
3679  {
3680  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3681  }
3682  else if(Next.SigAspect == TTrackElement::GroundSignal)
3683  {
3684  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3685  }
3686  else // 4 aspect
3687  {
3688  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3689  }
3690  break;
3691  }
3692  }
3693  }
3694  else
3695  {
3696  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3697  }
3698  }
3699  }
3700  if(OldTransparentColour != clB5G5R5)
3701  {
3702  Utilities->clTransparent = OldTransparentColour; // restore
3705  }
3706  Utilities->CallLogPop(1533);
3707 }
3708 
3709 // ---------------------------------------------------------------------------
3710 
3711 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
3712 {
3713  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
3714  if(UserGraphicVector.empty())
3715  {
3716  Utilities->CallLogPop(2192);
3717  return;
3718  }
3719  else
3720  {
3721  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3722  {
3723  Bitmap->Canvas->CopyMode = cmSrcCopy;
3724  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
3725  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
3726  }
3727  }
3728  Utilities->CallLogPop(2193);
3729 }
3730 
3731 // ---------------------------------------------------------------------------
3732 
3733 void TTrack::WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3734 /*
3735  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3736  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
3737 */
3738 {
3739  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackToImage");
3740 // need to change graphics back to black on white if have a dark background
3741  TColor OldTransparentColour = Utilities->clTransparent;
3742 
3744  {
3745  Utilities->clTransparent = TColor(0xFFFFFF); // white
3748  }
3749  TTrackElement Next;
3750 
3751  Bitmap->Canvas->CopyMode = cmSrcCopy;
3753  Graphics::TBitmap *GraphicOutput;
3754 
3755  while(ReturnNextInactiveTrackElement(3, Next))
3756  {
3757  GraphicOutput = Next.GraphicPtr; // no striped name graphics
3758  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3759  {
3760  if(Next.SpeedTag == 144) // level crossing
3761  {
3762  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
3763  if(BaseElement == 1) // hor element
3764  {
3765  if(Next.Attribute == 1) // open to trains
3766  {
3767  GraphicOutput = RailGraphics->LCBothHor;
3768  }
3769  else // plot as closed to trains if in any other state
3770  {
3771  GraphicOutput = RailGraphics->LCBothVer;
3772  }
3773  }
3774  else // vert element
3775  {
3776  if(Next.Attribute == 1) // open to trains
3777  {
3778  GraphicOutput = RailGraphics->LCBothVer;
3779  }
3780  else // plot as closed to trains if in any other state
3781  {
3782  GraphicOutput = RailGraphics->LCBothHor;
3783  }
3784  }
3785  }
3786  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3787  }
3788  }
3789 
3790  NextTrackElementPtr = TrackVector.begin();
3791  while(ReturnNextTrackElement(3, Next))
3792  {
3793  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3794  {
3795  if(Next.TrackType == Points) // plot active fillet
3796  {
3797  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3798  if(Next.SpeedTag < 28)
3799  {
3800  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3802  }
3803  else if(Next.SpeedTag < 132)
3804  {
3805  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3807  }
3808  else
3809  {
3810  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3812  }
3813  }
3814  else if(Next.TrackType == GapJump) // plot as connected
3815  {
3816  if(Next.SpeedTag == 88)
3817  {
3818  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3819  }
3820  else if(Next.SpeedTag == 89)
3821  {
3822  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3823  }
3824  else if(Next.SpeedTag == 90)
3825  {
3826  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3827  }
3828  else if(Next.SpeedTag == 91)
3829  {
3830  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3831  }
3832  else if(Next.SpeedTag == 92)
3833  {
3834  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3835  }
3836  else if(Next.SpeedTag == 93)
3837  {
3838  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3839  }
3840  else if(Next.SpeedTag == 94)
3841  {
3842  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3843  }
3844  else if(Next.SpeedTag == 95)
3845  {
3846  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3847  }
3848  }
3849  else if(Next.TrackType == SignalPost) // plot in correct colour
3850  {
3851  for(int x = 0; x < 40; x++)
3852  {
3853  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
3854  {
3855  // plot blank first, then plot platform if present - (always not striped for operating railway)
3856  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3857  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3858  int HOffset = 0;
3859  if(Next.SpeedTag > 73)
3860  HOffset = 5;
3861  else if(Next.SpeedTag == 71)
3862  HOffset = 9;
3863  int VOffset = 0;
3864  if(Next.SpeedTag == 69)
3865  VOffset = 9;
3866  else if(Next.SpeedTag == 72)
3867  VOffset = 5;
3868  else if(Next.SpeedTag == 74)
3869  VOffset = 5;
3870  Graphics::TBitmap *GraphicPtr;
3871  if(Next.SpeedTag > 71)
3872  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3873  else if(Next.SpeedTag < 70)
3874  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3875  else
3876  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3877  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3878  // plot special signal platform if present
3879  Graphics::TBitmap* SignalPlatformGraphic;
3880  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3881  {
3882  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3883  }
3884  // now plot signal (double yellow overwrites most of signal platform if present)
3885  // below amended for version 0.6
3887  {
3888  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
3889  }
3890  else if(Next.SigAspect == TTrackElement::TwoAspect)
3891  {
3892  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
3893  }
3894  else if(Next.SigAspect == TTrackElement::GroundSignal)
3895  {
3896  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3897  }
3898  else // 4 aspect
3899  {
3900  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
3901  }
3902  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
3903  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
3904  {
3905  if(Next.SpeedTag == 68)
3906  {
3907  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
3908  }
3909  if(Next.SpeedTag == 69)
3910  {
3911  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
3912  }
3913  if(Next.SpeedTag == 70)
3914  {
3915  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
3916  }
3917  if(Next.SpeedTag == 71)
3918  {
3919  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
3920  }
3921  if(Next.SpeedTag == 72)
3922  {
3923  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
3924  }
3925  if(Next.SpeedTag == 73)
3926  {
3927  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
3928  }
3929  if(Next.SpeedTag == 74)
3930  {
3931  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
3932  }
3933  if(Next.SpeedTag == 75)
3934  {
3935  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
3936  }
3937  }
3938  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
3939  {
3940  for(int x = 0; x < 40; x++)
3941  {
3942  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
3943  {
3944  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3945  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
3946  Utilities->RHSignalFlag); // in case existing signal is a double yellow
3947  // plot special signal platform if present
3948  Graphics::TBitmap* SignalPlatformGraphic;
3949  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
3950  {
3951  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
3952  }
3953  // now plot signal
3954  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
3955  break;
3956  }
3957  }
3958  }
3959  break;
3960  }
3961  }
3962  }
3963  else
3964  {
3965  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3966  }
3967  }
3968  }
3969  if(OldTransparentColour != clB5G5R5)
3970  {
3971  Utilities->clTransparent = OldTransparentColour; // restore
3974  }
3975  Utilities->CallLogPop(1701);
3976 }
3977 
3978 // ---------------------------------------------------------------------------
3979 
3980 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
3981 {
3982  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
3983  for(unsigned int x = 0; x < TrackVector.size(); x++)
3984  {
3985  if(TrackVector.at(x).TrackType == GapJump)
3986  {
3987  if(TrackVector.at(x).Conn[0] > -1)
3988  continue; // to next 'x' value as this element has already been set
3989  // here if identify a GapJump element not yet set
3990  GapPos = x;
3991  GapHLoc = TrackVector.at(x).HLoc;
3992  GapVLoc = TrackVector.at(x).VLoc;
3993  // highlight it
3995  Utilities->CallLogPop(469);
3996  return true;
3997  }
3998  }
3999  Utilities->CallLogPop(470);
4000  return false;
4001 }
4002 
4003 // ---------------------------------------------------------------------------
4004 
4005 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4006 {
4007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4008  AnsiString(VLoc));
4009  int Position;
4010  TTrackElement TrackElement;
4011 
4012  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4013  {
4014  Utilities->CallLogPop(471);
4015  return false; // not found
4016  }
4017  if(TrackElement.TrackType != GapJump)
4018  {
4019  Utilities->CallLogPop(472);
4020  return false; // found something but not a gap
4021  }
4022  if(Position == GapPos)
4023  {
4024  Utilities->CallLogPop(473);
4025  return false; // selected original gap
4026  }
4027  if(TrackVector.at(Position).Conn[0] != -1)
4028  {
4029  Utilities->CallLogPop(474);
4030  return false; // already selected
4031  }
4032  TrackVector.at(Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4033  TrackVector.at(Position).ConnLinkPos[0] = 0;
4034  TrackVector.at(GapPos).Conn[0] = Position; // set other one similarly
4035  TrackVector.at(GapPos).ConnLinkPos[0] = 0;
4036 // now highlight the selected location
4037  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4038  Utilities->CallLogPop(475);
4039  return true;
4040 }
4041 
4042 // ---------------------------------------------------------------------------
4043 
4044 bool TTrack::GapsUnset(int Caller)
4045  // returns true if there are gaps and any are unset
4046 {
4047  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4048  if(TrackVector.size() == 0)
4049  {
4050  Utilities->CallLogPop(476);
4051  return false;
4052  }
4053  for(unsigned int x = 0; x < TrackVector.size(); x++)
4054  {
4055  if(TrackVector.at(x).TrackType == GapJump)
4056  {
4057  if(TrackVector.at(x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4058  {
4059  Utilities->CallLogPop(477);
4060  return true;
4061  }
4062  else // set, but may not have matching element, or that element may not be set
4063  {
4064  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4065  // check that the element pointed to by the gap link is a GapJump
4066  {
4067  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4068  Utilities->CallLogPop(1137);
4069  return false;
4070  }
4071 // here if gap connection is itself a GapJump
4072  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4073  // check that the element pointed to by the gap link is a GapJump & that its gap link
4074  // points back to 'x'
4075  {
4076  Utilities->CallLogPop(478);
4077  return true;
4078  }
4079 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4080  }
4081  } // if(TrackVector.at(x).TrackType == GapJump)
4082  } // for x...
4083  Utilities->CallLogPop(479);
4084  return false;
4085 }
4086 
4087 // ---------------------------------------------------------------------------
4088 
4089 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4090 {
4091  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4092  for(unsigned int x = 0; x < TrackVector.size(); x++)
4093  {
4094  if(TrackVector.at(x).TrackType == GapJump)
4095  {
4096  Utilities->CallLogPop(1105);
4097  return false;
4098  }
4099  }
4100  Utilities->CallLogPop(1106);
4101  return true;
4102 }
4103 
4104 // ---------------------------------------------------------------------------
4105 
4106 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4107 {
4108  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4109  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4110  {
4111  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4112  {
4113  Utilities->CallLogPop(1107);
4114  return false;
4115  }
4116  }
4117  for(unsigned int x = 0; x < TrackVector.size(); x++)
4118  {
4119  if(TrackVector.at(x).FixedNamedLocationElement)
4120  {
4121  Utilities->CallLogPop(1108);
4122  return false;
4123  }
4124  }
4125  Utilities->CallLogPop(1109);
4126  return true;
4127 }
4128 
4129 // ---------------------------------------------------------------------------
4130 
4132  // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4133  // returns false otherwise or if there are no NamedLocationElements
4134 {
4135  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4136  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4137  {
4138  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4139  {
4140  if(InactiveTrackVector.at(x).LocationName == "")
4141  {
4142  Utilities->CallLogPop(1110);
4143  return true;
4144  }
4145  }
4146  }
4147  for(unsigned int x = 0; x < TrackVector.size(); x++)
4148  {
4149  if(TrackVector.at(x).FixedNamedLocationElement)
4150  {
4151  if(TrackVector.at(x).LocationName == "")
4152  {
4153  Utilities->CallLogPop(1111);
4154  return true;
4155  }
4156  }
4157  }
4158  Utilities->CallLogPop(1112);
4159  return false;
4160 }
4161 
4162 // ---------------------------------------------------------------------------
4163 
4164 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4165 {
4166  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4167  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4168  Utilities->CallLogPop(480);
4169 }
4170 
4171 // ---------------------------------------------------------------------------
4172 
4174 {
4175  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4176  if(TrackVector.size() == 0)
4177  {
4178  Utilities->CallLogPop(481);
4179  return;
4180  }
4181  for(unsigned int x = 0; x < TrackVector.size(); x++)
4182  {
4183  if(TrackVector.at(x).TrackType == GapJump)
4184  {
4185  if(TrackVector.at(x).Conn[0] > -1) // set
4186  {
4187  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4188  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4189  {
4190  TrackVector.at(x).Conn[0] = -1;
4191  TrackVector.at(x).ConnLinkPos[0] = -1;
4192  continue; // to next 'x'
4193  }
4194 // here if gap connection is itself a GapJump
4195  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4196  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4197  // if not clear Conns & CLks
4198  {
4199  TrackVector.at(x).Conn[0] = -1;
4200  TrackVector.at(x).ConnLinkPos[0] = -1;
4201  continue; // to next 'x'
4202  }
4203 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4204 // hence no more action needed on these Conns & CLks
4205  }
4206  } // else //gap jump
4207  } // for x...
4208 // throw Exception("Test Exception");//test
4209  Utilities->CallLogPop(482);
4210 }
4211 
4212 // ---------------------------------------------------------------------------
4213 
4214 void TTrack::ResetSignals(int Caller)
4215 {
4216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4217  for(unsigned int x = 0; x < TrackVector.size(); x++)
4218  {
4219  if(TrackVector.at(x).TrackType == SignalPost)
4220  {
4221  TrackVector.at(x).Attribute = 0;
4222  }
4223  }
4224  Utilities->CallLogPop(483);
4225 }
4226 
4227 // ---------------------------------------------------------------------------
4228 
4229 void TTrack::ResetPoints(int Caller)
4230 {
4231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4232  for(unsigned int x = 0; x < TrackVector.size(); x++)
4233  {
4234  if(TrackVector.at(x).TrackType == Points)
4235  {
4236  TrackVector.at(x).Attribute = 0;
4237  }
4238  }
4239  Utilities->CallLogPop(484);
4240 }
4241 
4242 // ---------------------------------------------------------------------------
4243 
4244 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4245 {
4246  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4247  if(TrackVector.empty())
4248  {
4249  TrackMap.clear();
4250  Utilities->CallLogPop(485);
4251  return true;
4252  }
4253 
4254 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4255  THVPair TrackMapKeyPair;
4256 
4257  NewVector.clear();
4258  TTrackMapIterator TrackMapPtr;
4259 
4260  if(!TrackMap.empty())
4261  {
4262  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4263  {
4264  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4265  }
4266  }
4267  if(NewVector.size() != TrackMap.size())
4268  {
4269  throw Exception("Error - Map & Vector different sizes");
4270  }
4271  unsigned int NonZeroCount = 0;
4272 
4273  for(unsigned int x = 0; x < TrackVector.size(); x++)
4274  {
4275  if(TrackVector.at(x).TrackType != Erase)
4276  NonZeroCount++;
4277  }
4278  if(NewVector.size() != NonZeroCount)
4279  {
4280  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4281  }
4282 
4284  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4285  TTrackMapEntry TrackMapEntry;
4286 
4287  for(unsigned int x = 0; x < TrackVector.size(); x++)
4288  {
4289  TrackMapKeyPair.first = TrackVector.at(x).HLoc;
4290  TrackMapKeyPair.second = TrackVector.at(x).VLoc;
4291  TrackMapEntry.first = TrackMapKeyPair;
4292  TrackMapEntry.second = x;
4293  if(!(TrackMap.insert(TrackMapEntry).second))
4294  {
4295  throw Exception("Error - map insertion failure, TrackVector in error");
4296  }
4297  }
4298 // All track now relocated in TrackVector, reset all Conns & CLks
4299  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4300  {
4301  for(unsigned int y = 0; y < 4; y++)
4302  {
4303  TrackVector.at(x).Conn[y] = -1;
4304  TrackVector.at(x).ConnLinkPos[y] = -1;
4305  }
4306  }
4307  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4308  CheckMapAndTrack(4); // test
4309  CheckMapAndInactiveTrack(4); // test
4310  CheckLocationNameMultiMap(8); // test
4311  if(!ResetGapsFromGapMap(1))
4312  {
4313  Utilities->CallLogPop(489);
4314  return false;
4315  }
4316  Utilities->CallLogPop(490);
4317  return true;
4318 }
4319 
4320 // ---------------------------------------------------------------------------
4321 
4322 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4323 {
4324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4325  GapMap.clear();
4326  THVPair GapMapKeyPair, GapMapValuePair;
4327  TGapMapEntry GapMapEntry;
4328 
4329  for(unsigned int x = 0; x < TrackVector.size(); x++)
4330  {
4331  if(TrackVector.at(x).TrackType == GapJump)
4332  {
4333  GapMapKeyPair.first = TrackVector.at(x).HLoc;
4334  GapMapKeyPair.second = TrackVector.at(x).VLoc;
4335  GapMapEntry.first = GapMapKeyPair;
4336  if(TrackVector.at(x).Conn[0] == -1)
4337  {
4338  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4339  }
4340  GapMapValuePair.first = TrackElementAt(7, TrackVector.at(x).Conn[0]).HLoc;
4341  GapMapValuePair.second = TrackElementAt(8, TrackVector.at(x).Conn[0]).VLoc;
4342  GapMapEntry.second = GapMapValuePair;
4343  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4344  {
4345  GapMap.insert(GapMapEntry);
4346  }
4347  }
4348  }
4349  Utilities->CallLogPop(492);
4350 }
4351 
4352 // ---------------------------------------------------------------------------
4353 
4354 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4355 {
4356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4357  LocError = false;
4358  bool CheckForLinks = false;
4359 
4360  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4361  {
4362  if(TrackVector.at(x).TrackType == Erase) //Erase isn't used any more as a track type
4363  continue; // skip blank elements
4364 // check footcrossing linkages
4365  if(TrackVector.at(x).TrackType == FootCrossing)
4366  {
4367  if(!CheckFootCrossingLinks(1, TrackVector.at(x)))
4368  {
4369  ShowMessage(
4370  "Footbridge or underpass connection error. Each end must connect to a platform, concourse or other footbridge or underpass, and they can't connect to each other");
4371  HLoc = TrackVector.at(x).HLoc;
4372  VLoc = TrackVector.at(x).VLoc;
4373  LocError = true;
4374  Utilities->CallLogPop(493);
4375  return false;
4376  }
4377  }
4378  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4379  {
4380  CheckForLinks = false;
4381  if(TrackVector.at(x).Link[y] <= 0)
4382  continue; // no link
4383  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4384  continue; // buffer
4385  if(TrackVector.at(x).Config[y] == Gap)
4386  continue; // gaps set later from GapMap
4387 
4388  // get required H & V for track element joining link 'y'
4389  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4390  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4391  // find track element if present
4392  bool ConnectionFoundFlag;
4393  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4394  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4395  {
4396  ShowMessage("Can't have a track element adjacent to a continuation exit");
4397  HLoc = TrackVector.at(x).HLoc;
4398  VLoc = TrackVector.at(x).VLoc;
4399  LocError = true;
4400  if(FinalCall)
4401  {
4402  throw Exception("Error in final track linkage - continuation adjacent to another element");
4403  }
4404  Utilities->CallLogPop(1539);
4405  return false;
4406  }
4407  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4408  continue;
4409  if(ConnectionFoundFlag)
4410  {
4411  TrackVector.at(x).Conn[y] = VecPos;
4412  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4413  bool LinkFoundFlag = false;
4414  if((TrackVector.at(x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4415  { // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4416  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4417  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4418  }
4419  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover))
4420  && (TrackVector.at(VecPos).TrackType == Buffers))
4421  {
4422  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4423  // need room for a train (2 elements) without fouling points or signals
4424  }
4425  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4426  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4427  {
4428  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4429  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4430  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4431  // be named but needs the adjacent element named too
4432  }
4433  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4434  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4435  {
4436  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4437  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4438  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4439  }
4440  else if((TrackVector.at(x).Config[y] == Signal) && (TrackVector.at(VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4441  {
4442  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4443  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4444  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4445  }
4446  else if(IsLCAtHV(45, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(46, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4447  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4448  {
4449  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4450  }
4451  else
4452  CheckForLinks = true;
4453  if(CheckForLinks)
4454  {
4455  for(unsigned int a = 0; a < 4; a++)
4456  {
4457  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4458  (TrackVector.at(VecPos).Config[a] != Gap))
4459  {
4460  TrackVector.at(x).ConnLinkPos[y] = a;
4461  // note - this ensures that if the connecting element is a leading point
4462  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4463  // (Points have the same link value for both [0] and [2])
4464  LinkFoundFlag = true;
4465  break; // stop after first find or will find later link for leading point
4466  }
4467  }
4468  }
4469  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4470  if(!LinkFoundFlag)
4471  {
4472  HLoc = TrackVector.at(x).HLoc;
4473  VLoc = TrackVector.at(x).VLoc;
4474  LocError = true;
4475  if(FinalCall)
4476  {
4477  throw Exception("Error in final track linkage - invalid link");
4478  }
4479  Utilities->CallLogPop(494);
4480  return false;
4481  }
4482  }
4483  // if there isn't a connection set the invert values for the offending element
4484  else // if(ConnectionFoundFlag)
4485  {
4486  HLoc = TrackVector.at(x).HLoc;
4487  VLoc = TrackVector.at(x).VLoc;
4488  LocError = true;
4489  if(FinalCall)
4490  {
4491  throw Exception("Error in final track linkage - connection not found");
4492  }
4493  Utilities->CallLogPop(495);
4494  return false;
4495  }
4496  }
4497  } // for(unsigned int x=0;x<TrackVector.size();x++)
4498 
4499  if(FinalCall)
4501 
4502 // final check
4503  bool ConnErrorFlag = false;
4504 
4505  for(unsigned int x = 0; x < TrackVector.size(); x++)
4506  {
4507  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4508  ConnErrorFlag = true;
4509  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4510  ConnErrorFlag = true;
4511  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4512  ConnErrorFlag = true;
4513  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4514  ConnErrorFlag = true;
4515  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4516  {
4517  if(TrackVector.at(x).ActiveTrackElementName == "")
4518  {
4519  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4520  {
4521  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4522  }
4523  }
4524  }
4525  }
4526  if(ConnErrorFlag)
4527  {
4528  if(FinalCall)
4529  {
4530  throw Exception("ConnError in LinkTrack - Final");
4531  }
4532  else
4533  {
4534  throw Exception("ConnError in LinkTrack - Precheck");
4535  }
4536  }
4537 
4538  bool CLkErrorFlag = false;
4539 
4540  for(unsigned int x = 0; x < TrackVector.size(); x++)
4541  {
4542  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4543  CLkErrorFlag = true;
4544  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4545  CLkErrorFlag = true;
4546  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4547  CLkErrorFlag = true;
4548  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4549  CLkErrorFlag = true;
4550  }
4551 
4552  if(CLkErrorFlag)
4553  {
4554  if(FinalCall)
4555  {
4556  throw Exception("CLkError in LinkTrack - Final");
4557  }
4558  else
4559  {
4560  throw Exception("CLkError in LinkTrack - Precheck");
4561  }
4562  }
4563 
4564 // set element lengths to min of 20m
4565  for(unsigned int x = 0; x < TrackVector.size(); x++)
4566  {
4567  if(TrackVector.at(x).TrackType == Erase)
4568  continue; // skip blank elements
4569  if(TrackVector.at(x).Length01 < 20)
4570  TrackVector.at(x).Length01 = 20;
4571  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4572  TrackVector.at(x).Length23 = 20;
4573  }
4574 
4575  if(FinalCall) // ONLY at FinalCall, no point calling twice
4576  {
4577  CalcHLocMinEtc(3);
4578  }
4579  Utilities->CallLogPop(497);
4580  return true;
4581 }
4582 
4583 // ---------------------------------------------------------------------------
4584 
4585 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
4586 {
4587  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
4588  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4589  {
4590  if(TrackVector.at(x).TrackType == Erase)
4591  continue; // skip blank elements
4592 
4593 // check footcrossing linkages
4594  if(TrackVector.at(x).TrackType == FootCrossing)
4595  {
4596  if(!CheckFootCrossingLinks(3, TrackVector.at(x)))
4597  {
4598  Utilities->CallLogPop(1127);
4599  return false;
4600  }
4601  }
4602 
4603  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4604  {
4605  if(TrackVector.at(x).Link[y] <= 0)
4606  continue; // no link
4607  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4608  continue; // buffer
4609  if(TrackVector.at(x).Config[y] == Gap)
4610  continue; // gaps set later from GapMap
4611 
4612  // get required H & V for track element joining link 'y'
4613  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4614  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4615  // find track element if present
4616  bool ConnectionFoundFlag;
4617  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
4618  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4619  {
4620  if(FinalCall)
4621  {
4622  throw Exception("Error in final track linkage - continuation adjacent to another element");
4623  }
4624  Utilities->CallLogPop(1540);
4625  return false;
4626  }
4627  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4628  continue;
4629  if(ConnectionFoundFlag)
4630  {
4631  TrackVector.at(x).Conn[y] = VecPos;
4632  bool LinkFoundFlag = false;
4633  // find connecting link in the newly found track element if there is one & make checks
4634  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4635  (TrackVector.at(VecPos).TrackType == Buffers))
4636  {
4637  Utilities->CallLogPop(1541);
4638  return false;
4639  }
4640  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4641  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4642  {
4643  Utilities->CallLogPop(1542);
4644  return false;
4645  }
4646  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4647  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4648  {
4649  Utilities->CallLogPop(1543);
4650  return false;
4651  }
4652  else if(IsLCAtHV(47, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(48, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4653  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4654  {
4655  Utilities->CallLogPop(1981);
4656  return false;
4657  }
4658 /* remove this restriction now that not permitted to treat a named continuation as a location stop
4659  else if(TrackVector.at(x).TrackType == Continuation)
4660  {
4661  int H = TrackVector.at(x).HLoc;
4662  int V = TrackVector.at(x).VLoc;
4663  bool FoundFlag = false;
4664  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
4665  if(FoundFlag)
4666  {
4667  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
4668  {
4669  int NewH = TrackElementAt(727, (TrackVector.at(x).Conn[1])).HLoc;
4670  int NewV = TrackElementAt(728, (TrackVector.at(x).Conn[1])).VLoc;
4671  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
4672  if(FoundFlag)
4673  {
4674  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
4675  {
4676  Utilities->CallLogPop(1544);
4677  return false;
4678  }
4679  }
4680  else
4681  {
4682  Utilities->CallLogPop(1545);
4683  return false;
4684  }
4685  }
4686  }
4687  }
4688 */
4689  for(unsigned int a = 0; a < 4; a++)
4690  {
4691  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4692  (TrackVector.at(VecPos).Config[a] != Gap))
4693  {
4694  TrackVector.at(x).ConnLinkPos[y] = a;
4695  // note - this ensures that if the connecting element is a leading point
4696  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4697  // (Points have the same link value for both [0] and [2])
4698  LinkFoundFlag = true;
4699  break; // stop after first find or will find later link for leading point
4700  }
4701  }
4702  if(!LinkFoundFlag)
4703  {
4704  if(FinalCall)
4705  {
4706  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
4707  }
4708  Utilities->CallLogPop(1128);
4709  return false;
4710  }
4711  }
4712  else // if(ConnectionFoundFlag)
4713  {
4714  if(FinalCall)
4715  {
4716  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
4717  }
4718  Utilities->CallLogPop(1129);
4719  return false;
4720  }
4721  }
4722  } // for(unsigned int x=0;x<TrackVector.size();x++)
4723 
4724  if(FinalCall)
4726 
4727 // final check
4728  bool ConnErrorFlag = false;
4729 
4730  for(unsigned int x = 0; x < TrackVector.size(); x++)
4731  {
4732  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4733  ConnErrorFlag = true;
4734  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4735  ConnErrorFlag = true;
4736  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4737  ConnErrorFlag = true;
4738  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4739  ConnErrorFlag = true;
4740  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4741  {
4742  if(TrackVector.at(x).ActiveTrackElementName == "")
4743  {
4744  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4745  {
4746  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4747  }
4748  }
4749  }
4750  }
4751  if(ConnErrorFlag)
4752  {
4753  if(FinalCall)
4754  {
4755  throw Exception("ConnError in LinkTrack - Final");
4756  }
4757  else
4758  {
4759  throw Exception("ConnError in LinkTrack - Precheck");
4760  }
4761  }
4762 
4763  bool CLkErrorFlag = false;
4764 
4765  for(unsigned int x = 0; x < TrackVector.size(); x++)
4766  {
4767  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4768  CLkErrorFlag = true;
4769  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4770  CLkErrorFlag = true;
4771  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4772  CLkErrorFlag = true;
4773  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4774  CLkErrorFlag = true;
4775  }
4776 
4777  if(CLkErrorFlag)
4778  {
4779  if(FinalCall)
4780  {
4781  throw Exception("CLkError in LinkTrack - Final");
4782  }
4783  else
4784  {
4785  throw Exception("CLkError in LinkTrack - Precheck");
4786  }
4787  }
4788 
4789 // set element lengths to min of 20m
4790  for(unsigned int x = 0; x < TrackVector.size(); x++)
4791  {
4792  if(TrackVector.at(x).TrackType == Erase)
4793  continue; // skip blank elements
4794  if(TrackVector.at(x).Length01 < 20)
4795  TrackVector.at(x).Length01 = 20;
4796  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4797  TrackVector.at(x).Length23 = 20;
4798  }
4799 
4800  if(FinalCall) // ONLY at FinalCall, no point calling twice
4801  {
4802  CalcHLocMinEtc(7);
4803  }
4804  Utilities->CallLogPop(1130);
4805  return true;
4806 }
4807 
4808 // ---------------------------------------------------------------------------
4809 
4810 bool TTrack::IsTrackLinked(int Caller) // not used any more
4811 {
4812  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
4813  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4814  {
4815  if(TrackVector.at(x).TrackType == Erase)
4816  {
4817  Utilities->CallLogPop(498);
4818  return false;
4819  }
4820 
4821 // check foot linkages
4822  if(TrackVector.at(x).TrackType == FootCrossing)
4823  {
4824  if(!CheckFootCrossingLinks(2, TrackVector.at(x)))
4825  {
4826  Utilities->CallLogPop(499);
4827  return false;
4828  }
4829  }
4830 
4831  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4832  {
4833  if(TrackVector.at(x).Link[y] <= 0)
4834  continue; // no link
4835  if(TrackVector.at(x).Config[y] == End)
4836  continue; // buffer or continuation
4837  if(TrackVector.at(x).Config[y] == Gap)
4838  continue; // gaps set later from GapMap
4839 
4840  // get required H & V for track element joining link 'y'
4841  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4842  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4843  // find track element if present
4844  bool ConnectionFoundFlag = false;
4845  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
4846  if(ConnectionFoundFlag)
4847  {
4848  TrackVector.at(x).Conn[y] = VecPos;
4849  // find connecting link in the newly found track element if there is one & make buffer check
4850  bool LinkFoundFlag = false;
4851  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
4852  (TrackVector.at(VecPos).TrackType == Buffers))
4853  {
4854  Utilities->CallLogPop(500);
4855  return false;
4856  }
4857  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4858  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4859  {
4860  Utilities->CallLogPop(501);
4861  return false;
4862  }
4863  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == Continuation))
4864  {
4865  Utilities->CallLogPop(502);
4866  return false;
4867  }
4868  else
4869  {
4870  for(unsigned int a = 0; a < 4; a++)
4871  {
4872  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4873  (TrackVector.at(VecPos).Config[a] != Gap))
4874  {
4875  TrackVector.at(x).ConnLinkPos[y] = a;
4876  // note - this ensures that if the connecting element is a leading point
4877  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4878  // (Points have the same link value for both [0] and [2])
4879  LinkFoundFlag = true;
4880  break; // stop after first find or will find later link for leading point
4881  }
4882  }
4883  }
4884  if(!LinkFoundFlag)
4885  {
4886  Utilities->CallLogPop(503);
4887  return false;
4888  }
4889  }
4890  else // if(ConnectionFoundFlag)
4891  {
4892  Utilities->CallLogPop(504);
4893  return false;
4894  }
4895  }
4896  } // for(unsigned int x=0;x<TrackVector.size();x++)
4897 
4898 // final check
4899  bool ConnErrorFlag = false;
4900 
4901  for(unsigned int x = 0; x < TrackVector.size(); x++)
4902  {
4903  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4904  ConnErrorFlag = true;
4905  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4906  ConnErrorFlag = true;
4907  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4908  ConnErrorFlag = true;
4909  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4910  ConnErrorFlag = true;
4911  }
4912  if(ConnErrorFlag)
4913  {
4914  Utilities->CallLogPop(505);
4915  return false;
4916  }
4917 
4918  bool CLkErrorFlag = false;
4919 
4920  for(unsigned int x = 0; x < TrackVector.size(); x++)
4921  {
4922  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4923  CLkErrorFlag = true;
4924  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4925  CLkErrorFlag = true;
4926  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4927  CLkErrorFlag = true;
4928  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4929  CLkErrorFlag = true;
4930  }
4931 
4932  if(CLkErrorFlag)
4933  {
4934  Utilities->CallLogPop(506);
4935  return false;
4936  }
4937  Utilities->CallLogPop(507);
4938  return true;
4939 }
4940 
4941 // ---------------------------------------------------------------------------
4942 
4944 {
4945  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
4946  int Position1, Position2;
4947  TTrackElement TrackElement1, TrackElement2;
4948  TGapMapIterator GapMapPtr;
4949 
4950  if(!GapMap.empty())
4951  {
4952  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
4953  {
4954  int HLoc1 = GapMapPtr->first.first;
4955  int VLoc1 = GapMapPtr->first.second;
4956  int HLoc2 = GapMapPtr->second.first;
4957  int VLoc2 = GapMapPtr->second.second;
4958  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
4959  {
4960  throw Exception("Failed to find H & V for gap1, GapMap in error");
4961  }
4962  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
4963  {
4964  throw Exception("Failed to find H & V for gap2, GapMap in error");
4965  }
4966  if(TrackElementAt(9, Position1).TrackType != GapJump)
4967  {
4968  throw Exception("Element at Pos1 not a gap, GapMap in error");
4969  }
4970  if(TrackElementAt(10, Position2).TrackType != GapJump)
4971  {
4972  throw Exception("Element at Pos2 not a gap, GapMap in error");
4973  }
4974  TrackElementAt(11, Position1).Conn[0] = Position2;
4975  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
4976  TrackElementAt(13, Position2).Conn[0] = Position1;
4977  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
4978  }
4979  }
4980  Utilities->CallLogPop(510);
4981  return true;
4982 }
4983 
4984 // ---------------------------------------------------------------------------
4985 
4986 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
4987 {
4988 // TIMPair MapEntry;
4989  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
4990  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
4991  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
4992  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
4993  TLocationNameMultiMapEntry LocationNameEntry;
4994 
4995  LocationNameEntry.first = TrackElement.LocationName;
4996  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
4997  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
4998  {
4999 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5000 // could arise when loading old railways with multiple NonStationNamedLocs
5001  bool FoundFlag = false;
5002  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5003  if(FoundFlag)
5004  {
5005  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5006  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5007  {
5008  Utilities->CallLogPop(1813);
5009  return;
5010  }
5011  }
5012  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5013  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5014  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5015  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5016  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5017  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5018  if(TrackElement.FixedNamedLocationElement)
5019  {
5020  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5021  LocationNameMultiMap.insert(LocationNameEntry);
5022  }
5023  if(TrackElement.HLoc < HLocMin)
5024  HLocMin = TrackElement.HLoc;
5025  if(TrackElement.HLoc > HLocMax)
5026  HLocMax = TrackElement.HLoc;
5027  if(TrackElement.VLoc < VLocMin)
5028  VLocMin = TrackElement.VLoc;
5029  if(TrackElement.VLoc > VLocMax)
5030  VLocMax = TrackElement.VLoc;
5031  }
5032  else
5033  {
5034 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5035 // shouldn't arise but leave in as a safeguard
5036  bool FoundFlag = false;
5037  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5038  if(FoundFlag)
5039  {
5040  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5041  {
5042  Utilities->CallLogPop(1814);
5043  return;
5044  }
5045  }
5046  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5047  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5048  {
5049  TrackMapKeyPair.first = TrackElement.HLoc;
5050  TrackMapKeyPair.second = TrackElement.VLoc;
5051  TrackMapEntry.first = TrackMapKeyPair;
5052  TrackMapEntry.second = TrackVector.size() - 1;
5053  TrackMap.insert(TrackMapEntry);
5054  if(TrackElement.FixedNamedLocationElement)
5055  {
5056  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap
5057  LocationNameMultiMap.insert(LocationNameEntry);
5058  }
5059  if(TrackElement.HLoc < HLocMin)
5060  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5061  if(TrackElement.HLoc > HLocMax)
5062  HLocMax = TrackElement.HLoc;
5063  if(TrackElement.VLoc < VLocMin)
5064  VLocMin = TrackElement.VLoc;
5065  if(TrackElement.VLoc > VLocMax)
5066  VLocMax = TrackElement.VLoc;
5067  }
5068  }
5069 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5070 // CheckMapAndInactiveTrack(6);//test
5071 
5072 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5073 // with the Platforms until layout fully loaded
5074  Utilities->CallLogPop(511);
5075 }
5076 
5077 // ---------------------------------------------------------------------------
5078 
5079 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5080 {
5081  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5082  AnsiString(VLoc));
5083  THVPair TrackMapKeyPair;
5084 
5085  FoundFlag = false;
5086  TTrackMapIterator TrackMapPtr;
5087 
5088  TrackMapKeyPair.first = HLoc;
5089  TrackMapKeyPair.second = VLoc;
5090  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5091  if(TrackMapPtr == TrackMap.end())
5092  {
5093  Utilities->CallLogPop(512);
5094  return -1; // nothing found
5095  }
5096  else
5097  {
5098  FoundFlag = true;
5099  Utilities->CallLogPop(513);
5100  return TrackMapPtr->second;
5101  }
5102 }
5103 
5104 // ---------------------------------------------------------------------------
5105 
5106 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5107 {
5108  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5109  AnsiString(VLoc));
5110  THVPair TrackMapKeyPair;
5111  TTrackMapIterator TrackMapPtr;
5112 
5113  TrackMapKeyPair.first = HLoc;
5114  TrackMapKeyPair.second = VLoc;
5115  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5116  if(TrackMapPtr == TrackMap.end())
5117  {
5118  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5119  throw Exception(Message);
5120  }
5121  else
5122  {
5123  Utilities->CallLogPop(1943);
5124  return TrackElementAt(871, TrackMapPtr->second);
5125  }
5126 }
5127 
5128 // ---------------------------------------------------------------------------
5129 
5131 {
5132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5133  AnsiString(VLoc));
5134  THVPair InactiveTrackMapKeyPair;
5135  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5136 
5137  InactiveTrackMapKeyPair.first = HLoc;
5138  InactiveTrackMapKeyPair.second = VLoc;
5139  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5140  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5141  {
5142  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5143  throw Exception(Message);
5144  }
5145  else
5146  {
5147  Utilities->CallLogPop(1949);
5148  return InactiveTrackElementAt(34, InactiveTrackMapPtr->second);
5149  }
5150 }
5151 
5152 // ---------------------------------------------------------------------------
5153 
5154 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5155 {
5156  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5157  bool Present = true;
5158  THVPair TrackMapKeyPair;
5159  TTrackMapIterator TrackMapPtr;
5160 
5161  TrackMapKeyPair.first = HLoc;
5162  TrackMapKeyPair.second = VLoc;
5163  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5164  if(TrackMapPtr == TrackMap.end())
5165  {
5166  Present = false;
5167  }
5168  Utilities->CallLogPop(2057);
5169  return Present;
5170 }
5171 
5172 // ---------------------------------------------------------------------------
5173 
5174 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5175 {
5176  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5177  AnsiString(VLoc));
5178  bool Present = true;
5179  THVPair InactiveTrackMapKeyPair;
5180  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5181 
5182  InactiveTrackMapKeyPair.first = HLoc;
5183  InactiveTrackMapKeyPair.second = VLoc;
5184  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5185  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5186  {
5187  Present = false;
5188  }
5189  Utilities->CallLogPop(2058);
5190  return Present;
5191 }
5192 
5193 // ---------------------------------------------------------------------------
5194 
5195 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5196  // max number of elements is 2, for platforms
5197  // note that both elements of RetPair may be the same, if only one present in map
5198 {
5199  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5200  AnsiString(VLoc));
5201  THVPair InactiveTrackMapKeyPair;
5202  TIMPair RetPair;
5203  TInactiveTrackRange InactiveTrackRange;
5204 
5205  FoundFlag = false;
5206  InactiveTrackMapKeyPair.first = HLoc;
5207  InactiveTrackMapKeyPair.second = VLoc;
5208  if(InactiveTrack2MultiMap.empty())
5209  {
5210  RetPair.first = 0;
5211  RetPair.second = 0;
5212  Utilities->CallLogPop(1815);
5213  return RetPair; // map empty
5214  }
5215  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5216  if(InactiveTrackRange.first == InactiveTrackRange.second)
5217  {
5218  RetPair.first = 0;
5219  RetPair.second = 0;
5220  Utilities->CallLogPop(514);
5221  return RetPair; // nothing found
5222  }
5223  else
5224  {
5225  RetPair.first = InactiveTrackRange.first->second;
5226  RetPair.second = (--InactiveTrackRange.second)->second;
5227  FoundFlag = true;
5228  Utilities->CallLogPop(515);
5229  return RetPair;
5230  }
5231 }
5232 
5233 // ---------------------------------------------------------------------------
5234 
5235 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5236 {
5237 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5238  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5239  AnsiString(DivergingPosition));
5240  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5241  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5242  int SpeedTag1 = T1.SpeedTag;
5243  int SpeedTag2 = T2.SpeedTag;
5244 
5245  if(T1.Attribute != T2.Attribute)
5246  {
5247  Utilities->CallLogPop(516);
5248  return false;
5249  }
5250  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5251  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5252  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5253  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5254  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5255  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5256  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5257  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5258  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5259  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5260  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5261  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5262  {
5263  Utilities->CallLogPop(517);
5264  return true;
5265  }
5266  else
5267  {
5268  Utilities->CallLogPop(518);
5269  return false;
5270  }
5271 }
5272 
5273 // ---------------------------------------------------------------------------
5274 
5275 /*
5276  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5277  {
5278  if(lower.second < higher.second) return true;
5279  else if(lower.second > higher.second) return false;
5280  else if(lower.second == higher.second)
5281  {
5282  if(lower.first < higher.first) return true;
5283  }
5284  return false;
5285  }
5286 */
5287 // ---------------------------------------------------------------------------
5288 
5289 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5290  // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5291 {
5292  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5293  if(TrackElement.TrackType != GapJump)
5294  {
5295  throw Exception("Error, Wrong track type in PlotGap");
5296  }
5297  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5298  {
5299  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5300  }
5301  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5302  {
5303  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5304  }
5305  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5306  {
5307  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5308  }
5309  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5310  {
5311  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5312  }
5313  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5314  {
5315  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5316  }
5317  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5318  {
5319  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5320  }
5321  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5322  {
5323  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5324  }
5325  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5326  {
5327  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5328  }
5329  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5330  {
5331  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5332  }
5333  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5334  {
5335  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5336  }
5337  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5338  {
5339  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5340  }
5341  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5342  {
5343  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5344  }
5345  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5346  {
5347  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5348  }
5349  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5350  {
5351  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5352  }
5353  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5354  {
5355  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5356  }
5357  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5358  {
5359  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5360  }
5361  Utilities->CallLogPop(1101);
5362 }
5363 
5364 // ---------------------------------------------------------------------------
5365 
5366 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5367 {
5368  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5369  if(TrackElement.TrackType != Points)
5370  {
5371  throw Exception("Error, Wrong track type in PlotPoints");
5372  }
5373  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5374  TrackElement.PlotVariableTrackElement(4, Disp);
5375  if(BothFillets)
5376  {
5377  if(TrackElement.SpeedTag < 28)
5378  {
5379  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5380  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5381  }
5382  else if(TrackElement.SpeedTag < 132)
5383  {
5384  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5385  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5386  }
5387  else
5388  {
5389  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5390  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5391  }
5392  }
5393  else
5394  {
5395  if(TrackElement.SpeedTag < 28)
5396  {
5397  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5398  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5399  }
5400  else if(TrackElement.SpeedTag < 132)
5401  {
5402  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5403  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5404  }
5405  else
5406  {
5407  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5408  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5409  }
5410  }
5411 // replot platform if required
5412  TIMPair IMPair;
5413  bool FoundFlag;
5414 
5415  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5416  if(FoundFlag)
5417  { // only one platform possible at points so only need to plot IMPair.first
5418  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5419  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5420  }
5421  Utilities->CallLogPop(519);
5422 }
5423 
5424 // ---------------------------------------------------------------------------
5425 
5426 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5427 {
5428 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5429  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5430  if(TrackElement.TrackType != SignalPost)
5431  {
5432  throw Exception("Error, Wrong track type in PlotSignal");
5433  }
5434  for(int x = 0; x < 40; x++)
5435  {
5436  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5437  {
5438  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5439  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5440 // in case existing signal is a double yellow
5441  // plot platforms if present
5442 // Graphics::TBitmap* SignalPlatformGraphic;
5443 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5444 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
5445 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
5446 // to not be plotted with the above function.
5447  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
5448  // now plot signal (double yellow overwrites most of signal platform if present)
5449  // additions at version 0.6 for other aspects & ground sigs
5450  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
5451  {
5452  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
5453  }
5454  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
5455  {
5456  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
5457  }
5458  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
5459  {
5460  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5461  }
5462  else // 4 aspect
5463  {
5464  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
5465  }
5466  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
5467  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
5468  {
5469  if(TrackElement.SpeedTag == 68)
5470  {
5471  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
5472  }
5473  if(TrackElement.SpeedTag == 69)
5474  {
5475  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
5476  }
5477  if(TrackElement.SpeedTag == 70)
5478  {
5479  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
5480  }
5481  if(TrackElement.SpeedTag == 71)
5482  {
5483  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
5484  }
5485  if(TrackElement.SpeedTag == 72)
5486  {
5487  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
5488  }
5489  if(TrackElement.SpeedTag == 73)
5490  {
5491  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
5492  }
5493  if(TrackElement.SpeedTag == 74)
5494  {
5495  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
5496  }
5497  if(TrackElement.SpeedTag == 75)
5498  {
5499  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
5500  }
5501  }
5502  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
5503  // ground signal calling on, need to use normal proceed aspect
5504  {
5505  for(int x = 0; x < 40; x++)
5506  {
5507  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
5508  {
5509  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5510  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5511  // plot special signal platform if present
5512  Graphics::TBitmap* SignalPlatformGraphic;
5513  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
5514  // now plot signal
5515  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5516  }
5517  }
5518  }
5519  break;
5520  }
5521  }
5522  Utilities->CallLogPop(520);
5523 }
5524 
5525 // ---------------------------------------------------------------------------
5526 
5527 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
5528 {
5529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5530  bool FoundFlag;
5531  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
5532 
5533  if(!FoundFlag)
5534  {
5535  Utilities->CallLogPop(2112);
5536  return;
5537  }
5538  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
5539  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
5540 
5541  // don't want 'else if' for the below as may need to plot 2 platforms
5542  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
5543  {
5544  if(IAElement1.LocationName == "") // '2' will be same
5545  {
5546  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
5547  }
5548  else
5549  {
5550  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
5551  }
5552  }
5553  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
5554  {
5555  if(IAElement1.LocationName == "") // '2' will be same
5556  {
5557  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
5558  }
5559  else
5560  {
5561  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
5562  }
5563  }
5564  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
5565  {
5566  if(IAElement1.LocationName == "") // '2' will be same
5567  {
5568  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
5569  }
5570  else
5571  {
5572  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
5573  }
5574  }
5575  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
5576  {
5577  if(IAElement1.LocationName == "") // '2' will be same
5578  {
5579  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
5580  }
5581  else
5582  {
5583  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
5584  }
5585  }
5586  Utilities->CallLogPop(2113);
5587 }
5588 
5589 // ---------------------------------------------------------------------------
5590 
5591 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
5592 {
5593 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
5594  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
5595  AnsiString(VLoc));
5596 // find topmost LC, opening them all (to trains) in turn
5597  int UpStep = 0;
5598 
5599  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5600  {
5601  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
5602  UpStep--;
5603  }
5604 // now find bottommost LC, opening them all (to trains) in turn
5605  int DownStep = 1;
5606 
5607  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
5608  {
5609  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
5610  DownStep++;
5611  }
5612 // find leftmost LC, opening them all (to trains) in turn
5613  int LeftStep = 0;
5614 
5615  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
5616  {
5617  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
5618  LeftStep--;
5619  }
5620 // now find rightmost LC, opening them all (to trains) in turn
5621  int RightStep = 1;
5622 
5623  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
5624  {
5625  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
5626  RightStep++;
5627  }
5628  Utilities->CallLogPop(1915);
5629 }
5630 
5631 // ---------------------------------------------------------------------------
5632 
5633 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets ConsecSignals to 2 for all linked LCs
5634 {
5635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5636 // work upwards setting all to manual
5637  int UpStep = -1;
5638 
5639  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
5640  {
5641  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
5642  UpStep--;
5643  }
5644 // work downwards setting all to manual
5645  int DownStep = 1;
5646 
5647  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
5648  {
5649  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
5650  DownStep++;
5651  }
5652 // work leftwards setting all to manual
5653  int LeftStep = -1;
5654 
5655  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
5656  {
5657  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
5658  LeftStep--;
5659  }
5660 // work rightwards setting all to manual
5661  int RightStep = 1;
5662 
5663  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
5664  {
5665  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
5666  RightStep++;
5667  }
5668  Utilities->CallLogPop(2242);
5669 }
5670 
5671 // ---------------------------------------------------------------------------
5672 
5673 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
5674 {// Set ConsecSignals value to 2 to indicate barriers manually closed
5675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5676  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
5677  {
5678  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
5679  {
5680  BarriersDownVector.at(x).ConsecSignals = 2;
5681  break;
5682  }
5683  }
5684  Utilities->CallLogPop(2243);
5685 }
5686 
5687 // ---------------------------------------------------------------------------
5688 
5689 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
5690 {
5691  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5692 // work upwards
5693  int UpStep = 0; //start with this location
5694 
5695  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
5696  {
5697  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
5698  {
5699  Utilities->CallLogPop(2244);
5700  return true;
5701  }
5702  UpStep--;
5703  }
5704 // work downwards
5705  int DownStep = 1;
5706 
5707  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
5708  {
5709  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
5710  {
5711  Utilities->CallLogPop(2245);
5712  return true;
5713  }
5714  DownStep++;
5715  }
5716 // work leftwards
5717  int LeftStep = -1;
5718 
5719  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
5720  {
5721  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
5722  {
5723  Utilities->CallLogPop(2246);
5724  return true;
5725  }
5726  LeftStep--;
5727  }
5728 // work rightwards
5729  int RightStep = 1;
5730 
5731  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
5732  {
5733  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
5734  {
5735  Utilities->CallLogPop(2247);
5736  return true;
5737  }
5738  RightStep++;
5739  }
5740  Utilities->CallLogPop(2248);
5741  return false;
5742 }
5743 
5744 // ---------------------------------------------------------------------------
5745 
5746 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
5747 {
5748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5749  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
5750  {
5751  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).ConsecSignals == 2))
5752  {
5753  BDVectorPos = x;
5754  Utilities->CallLogPop(2249);
5755  return true;
5756  }
5757  }
5758  BDVectorPos = -1;
5759  Utilities->CallLogPop(2250);
5760  return false;
5761 }
5762 
5763 // ---------------------------------------------------------------------------
5764 
5765 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int ConsecSignals, TDisplay *Disp, bool Manual)
5766  // open to trains
5767  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
5768 {
5769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
5770  AnsiString(VLoc));
5771  if(!IsLCAtHV(4, HLoc, VLoc))
5772  {
5773  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
5774  }
5775  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
5776  {
5777  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
5778  }
5779 // check for adjacent LCs & if so open (to trains)
5780  if(BaseElementSpeedTag == 1) // hor track element
5781  {
5782  // find topmost LC, opening them all (to trains) in turn
5783  int UpStep = 0;
5784  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
5785  {
5786  UpStep--;
5787  }
5788  UpStep++;
5789  // now find bottommost LC, opening them all (to trains) in turn
5790  int DownStep = 1;
5791  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
5792  {
5793  DownStep++;
5794  }
5795  DownStep--;
5796  // now plot graphics, UpStep is smallest & DownStep largest
5797  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
5798  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
5799  Graphics::TBitmap *RouteGraphic;
5800  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
5801  if(ConsecSignals == 1)
5802  {
5803  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
5804  }
5805  else if(ConsecSignals == 0)
5806  {
5807  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
5808  }
5809  else //manual - no route
5810  {
5811  RouteGraphic = BaseGraphic;
5812  }
5813 // LinkSigRouteGraphicsPtr[0] hor } pref dir
5814 // LinkSigRouteGraphicsPtr[1] ver }
5815 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
5816 // LinkNonSigRouteGraphicsPtr[1] ver }
5817 
5818  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
5819  {
5820  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
5821  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
5822  if(!Manual)
5823  {
5824  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
5825  }
5826  else
5827  {
5828  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
5829  }
5830  }
5831  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
5832  {
5833  if(UpStep == 0)
5834  {
5835  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5836  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5837  if(!Manual)
5838  {
5839  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5840  }
5841  else
5842  {
5843  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5844  }
5845  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5846  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5847  if(!Manual)
5848  {
5849  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5850  }
5851  else
5852  {
5853  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5854  }
5855  }
5856  else
5857  {
5858  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5859  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5860  if(!Manual)
5861  {
5862  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5863  }
5864  else
5865  {
5866  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5867  }
5868  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5869  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5870  if(!Manual)
5871  {
5872  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5873  }
5874  else
5875  {
5876  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5877  }
5878  }
5879  }
5880  else // at least one plain graphic
5881  {
5882  if(UpStep == 0)
5883  {
5884  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5885  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
5886  if(!Manual)
5887  {
5888  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5889  }
5890  else
5891  {
5892  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5893  }
5894  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5895  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5896  if(!Manual)
5897  {
5898  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5899  }
5900  else
5901  {
5902  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5903  }
5904  }
5905  else if(DownStep == 0)
5906  {
5907  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5908  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5909  if(!Manual)
5910  {
5911  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5912  }
5913  else
5914  {
5915  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5916  }
5917  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5918  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
5919  if(!Manual)
5920  {
5921  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5922  }
5923  else
5924  {
5925  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5926  }
5927  }
5928  else
5929  {
5930  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
5931  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
5932  if(!Manual)
5933  {
5934  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
5935  }
5936  else
5937  {
5938  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
5939  }
5940  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
5941  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
5942  if(!Manual)
5943  {
5944  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
5945  }
5946  else
5947  {
5948  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
5949  }
5950  }
5951  for(int x = (UpStep + 1); x < DownStep; x++)
5952  {
5953  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
5954  if(x == 0)
5955  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
5956  else
5957  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
5958  if(!Manual)
5959  {
5960  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
5961  }
5962  else
5963  {
5964  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
5965  }
5966  }
5967  }
5968  Disp->Update();
5969  Utilities->CallLogPop(1958);
5970  return;
5971  }
5972 
5973  else // ver track element
5974  {
5975  // find leftmost LC, opening them all (to trains) in turn
5976  int LStep = 0;
5977  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
5978  {
5979  LStep--;
5980  }
5981  LStep++;
5982  // now find rightmost LC, opening them all (to trains) in turn
5983  int RStep = 1;
5984  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
5985  {
5986  RStep++;
5987  }
5988  RStep--;
5989  // now plot graphics, LStep is smallest & RStep largest
5990  Graphics::TBitmap *RouteGraphic;
5991  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
5992  if(ConsecSignals == 1)
5993  {
5994  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
5995  }
5996  else if(ConsecSignals == 0)
5997  {
5998  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
5999  }
6000  else //manual
6001  {
6002  RouteGraphic = BaseGraphic;
6003  }
6004 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6005 // LinkSigRouteGraphicsPtr[1] ver }
6006 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6007 // LinkNonSigRouteGraphicsPtr[1] ver }
6008  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6009  {
6010  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6011  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6012  if(!Manual)
6013  {
6014  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6015  }
6016  else
6017  {
6018  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6019  }
6020  }
6021  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6022  {
6023  if(LStep == 0)
6024  {
6025  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6026  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6027  if(!Manual)
6028  {
6029  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6030  }
6031  else
6032  {
6033  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6034  }
6035  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6036  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6037  if(!Manual)
6038  {
6039  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6040  }
6041  else
6042  {
6043  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6044  }
6045  }
6046  else
6047  {
6048  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6049  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6050  if(!Manual)
6051  {
6052  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6053  }
6054  else
6055  {
6056  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6057  }
6058  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6059  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6060  if(!Manual)
6061  {
6062  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6063  }
6064  else
6065  {
6066  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6067  }
6068  }
6069  }
6070  else // at least one plain graphic
6071  {
6072  if(LStep == 0)
6073  {
6074  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6075  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6076  if(!Manual)
6077  {
6078  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6079  }
6080  else
6081  {
6082  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6083  }
6084  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6085  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6086  if(!Manual)
6087  {
6088  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6089  }
6090  else
6091  {
6092  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6093  }
6094  }
6095  else if(RStep == 0)
6096  {
6097  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6098  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6099  if(!Manual)
6100  {
6101  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6102  }
6103  else
6104  {
6105  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6106  }
6107  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6108  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6109  if(!Manual)
6110  {
6111  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6112  }
6113  else
6114  {
6115  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6116  }
6117  }
6118  else
6119  {
6120  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6121  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6122  if(!Manual)
6123  {
6124  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6125  }
6126  else
6127  {
6128  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6129  }
6130  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6131  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6132  if(!Manual)
6133  {
6134  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6135  }
6136  else
6137  {
6138  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6139  }
6140  }
6141  for(int x = (LStep + 1); x < RStep; x++)
6142  {
6143  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6144  if(x == 0)
6145  {
6146  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6147  }
6148  else
6149  {
6150  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6151  }
6152  if(!Manual)
6153  {
6154  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6155  }
6156  else
6157  {
6158  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6159  }
6160  }
6161  }
6162  Disp->Update();
6163  Utilities->CallLogPop(1896);
6164  return;
6165  }
6166 }
6167 
6168 // ---------------------------------------------------------------------------
6169 
6170 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6171  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6172 {
6173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6174  AnsiString(HLoc) + "," + AnsiString(VLoc));
6175  if(!IsLCAtHV(29, HLoc, VLoc))
6176  {
6177  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6178  }
6179  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6180  {
6181  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6182  }
6183 // check for adjacent LCs & if so open (to trains)
6184  if(BaseElementSpeedTag == 1) // hor track element
6185  {
6186  // find topmost LC, opening them all (to trains) in turn
6187  int UpStep = 0;
6188  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6189  {
6190  UpStep--;
6191  }
6192  UpStep++;
6193  // now find bottommost LC, opening them all (to trains) in turn
6194  int DownStep = 1;
6195  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6196  {
6197  DownStep++;
6198  }
6199  DownStep--;
6200  // now plot graphics, UpStep is smallest & DownStep largest
6201  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6202  {
6203  if(!Manual)
6204  {
6205  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6206  }
6207  else
6208  {
6209  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6210  }
6211  }
6212  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6213  {
6214  if(!Manual)
6215  {
6216  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6217  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6218  }
6219  else
6220  {
6221  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6222  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6223  }
6224  }
6225  else // at least one plain graphic
6226  {
6227  if(!Manual)
6228  {
6229  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6230  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6231  for(int x = (UpStep + 1); x < DownStep; x++)
6232  {
6233  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6234  }
6235  }
6236  else
6237  {
6238  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6239  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6240  for(int x = (UpStep + 1); x < DownStep; x++)
6241  {
6242  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6243  }
6244  }
6245  }
6246  // set markers
6247  for(int x = UpStep; x <= DownStep; x++)
6248  {
6249  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6250  }
6251  Display->Update();
6252  Utilities->CallLogPop(1944);
6253  return;
6254  }
6255 
6256  else // ver track element
6257  {
6258  // find leftmost LC, opening them all (to trains) in turn
6259  int LStep = 0;
6260  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6261  {
6262  LStep--;
6263  }
6264  LStep++;
6265  // now find rightmost LC, opening them all (to trains) in turn
6266  int RStep = 1;
6267  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6268  {
6269  RStep++;
6270  }
6271  RStep--;
6272  // now plot graphics, LStep is smallest & RStep largest
6273  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6274  {
6275  if(!Manual)
6276  {
6277  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6278  }
6279  else
6280  {
6281  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6282  }
6283  }
6284  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6285  {
6286  if(!Manual)
6287  {
6288  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6289  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6290  }
6291  else
6292  {
6293  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6294  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6295  }
6296  }
6297  else // at least one plain graphic
6298  {
6299  if(!Manual)
6300  {
6301  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6302  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6303  for(int x = (LStep + 1); x < RStep; x++)
6304  {
6305  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6306  }
6307  }
6308  else
6309  {
6310  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6311  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6312  for(int x = (LStep + 1); x < RStep; x++)
6313  {
6314  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6315  }
6316  }
6317  }
6318  // set markers
6319  for(int x = LStep; x <= RStep; x++)
6320  {
6321  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6322  }
6323  Disp->Update();
6324  Utilities->CallLogPop(1945);
6325  return;
6326  }
6327 }
6328 
6329 // ---------------------------------------------------------------------------
6330 
6331 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6332  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6333 {
6334  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6335  AnsiString(VLoc));
6336  if(!IsLCAtHV(9, HLoc, VLoc))
6337  {
6338  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6339  }
6340  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6341  {
6342  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
6343  }
6344 // check for adjacent LCs & if so close (to trains)
6345  if(BaseElementSpeedTag == 1) // hor track element
6346  {
6347  // find topmost LC, closing them all (to trains) in turn
6348  int UpStep = 0;
6349  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6350  {
6351  UpStep--;
6352  }
6353  UpStep++;
6354  // now find bottommost LC, opening them all (to trains) in turn
6355  int DownStep = 1;
6356  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
6357  {
6358  DownStep++;
6359  }
6360  DownStep--;
6361  // now plot graphics, UpStep is smallest & DownStep largest
6362  for(int x = UpStep; x < (DownStep + 1); x++)
6363  {
6364  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6365  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
6366  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6367  }
6368  Disp->Update();
6369  Utilities->CallLogPop(1959);
6370  return;
6371  }
6372 
6373  else // ver track element
6374  {
6375  // find leftmost LC, closing them all (to trains) in turn
6376  int LStep = 0;
6377  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
6378  {
6379  LStep--;
6380  }
6381  LStep++;
6382  // now find rightmost LC, opening them all (to trains) in turn
6383  int RStep = 1;
6384  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6385  {
6386  RStep++;
6387  }
6388  RStep--;
6389  // now plot graphics, LStep is smallest & RStep largest
6390  for(int x = LStep; x < (RStep + 1); x++)
6391  {
6392  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6393  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6394  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6395  }
6396  Disp->Update();
6397  Utilities->CallLogPop(1960);
6398  return;
6399  }
6400 }
6401 
6402 // ---------------------------------------------------------------------------
6403 
6404 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6405  // closed to trains
6406  // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6407 {
6408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6409  AnsiString(HLoc) + "," + AnsiString(VLoc));
6410  if(!IsLCAtHV(34, HLoc, VLoc))
6411  {
6412  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6413  }
6414  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6415  {
6416  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6417  }
6418  TTrackElement TE;
6419 
6420 // check for adjacent LCs & if so close (to trains)
6421  if(BaseElementSpeedTag == 1) // hor track element
6422  {
6423  // find topmost LC, closing them all (to trains) in turn
6424  int UpStep = 0;
6425  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6426  {
6427  UpStep--;
6428  }
6429  UpStep++;
6430  // now find bottommost LC, opening them all (to trains) in turn
6431  int DownStep = 1;
6432  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6433  {
6434  DownStep++;
6435  }
6436  DownStep--;
6437  // now plot graphics, UpStep is smallest & DownStep largest
6438  for(int x = UpStep; x <= DownStep; x++)
6439  {
6440  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6441  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6442  }
6443  Display->Update();
6444  Utilities->CallLogPop(1946);
6445  return;
6446  }
6447 
6448  else // ver track element
6449  {
6450  // find leftmost LC, closing them all (to trains) in turn
6451  int LStep = 0;
6452  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
6453  {
6454  LStep--;
6455  }
6456  LStep++;
6457  // now find rightmost LC, opening them all (to trains) in turn
6458  int RStep = 1;
6459  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
6460  {
6461  RStep++;
6462  }
6463  RStep--;
6464  // now plot graphics, LStep is smallest & RStep largest
6465  for(int x = LStep; x <= RStep; x++)
6466  {
6467  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6468  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
6469  }
6470  Display->Update();
6471  Utilities->CallLogPop(1947);
6472  return;
6473  }
6474 }
6475 
6476 // ---------------------------------------------------------------------------
6477 
6478 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int ConsecSignals, TDisplay *Disp)
6479 {
6480  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6481  Graphics::TBitmap *RouteGraphic;
6482  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6483 
6484  if(BaseElementSpeedTag == 1)
6485  {
6486  if(ConsecSignals == 1)
6487  {
6488  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6489  }
6490  else if(ConsecSignals == 0)
6491  {
6492  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6493  }
6494  else //manual
6495  {
6496  RouteGraphic = BaseGraphic;
6497  }
6498 
6499  if(State == Raising)
6500  RouteGraphic = BaseGraphic;
6501  }
6502  else
6503  {
6504  BaseGraphic = RailGraphics->gl2;
6505  if(ConsecSignals == 1)
6506  {
6507  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6508  }
6509  else if(ConsecSignals == 0)
6510  {
6511  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6512  }
6513  else
6514  {
6515  RouteGraphic = BaseGraphic; //manual
6516  }
6517  if(State == Raising)
6518  RouteGraphic = BaseGraphic;
6519  }
6520  int UpStep = 0;
6521 
6522  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6523  {
6524  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6525  if(UpStep == 0)
6526  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6527  else
6528  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6529  UpStep--;
6530  }
6531 // now find bottommost LC, opening them all (to trains) in turn
6532  int DownStep = 1;
6533 
6534  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
6535  {
6536  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6537  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6538  DownStep++;
6539  }
6540  int LeftStep = 0;
6541 
6542  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6543  {
6544  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6545  if(LeftStep == 0)
6546  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
6547  else
6548  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
6549  LeftStep--;
6550  }
6551 // now find rightmost LC, opening them all (to trains) in turn
6552  int RightStep = 1;
6553 
6554  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
6555  {
6556  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6557  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
6558  RightStep++;
6559  }
6560  Disp->Update();
6561  Utilities->CallLogPop(1914);
6562 }
6563 
6564 // ---------------------------------------------------------------------------
6565 
6566 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
6567 {
6568 // return false for no LC there, flashing or a closed (to trains) LC
6569  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6570  bool FoundFlag;
6571  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
6572 
6573  if(!FoundFlag)
6574  {
6575  Utilities->CallLogPop(1898);
6576  return false;
6577  }
6578  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6579  {
6580  Utilities->CallLogPop(1899);
6581  return false;
6582  }
6583  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
6584  {
6585  Utilities->CallLogPop(1900);
6586  return true;
6587  }
6588  Utilities->CallLogPop(1901);
6589  return false;
6590 }
6591 
6592 // ---------------------------------------------------------------------------
6593 
6594 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
6595 {
6596 // return false for no LC there, flashing LC or open (to trains) LC
6597  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6598  bool FoundFlag;
6599  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
6600 
6601  if(!FoundFlag)
6602  {
6603  Utilities->CallLogPop(1922);
6604  return false;
6605  }
6606  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6607  {
6608  Utilities->CallLogPop(1923);
6609  return false;
6610  }
6611  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
6612  {
6613  Utilities->CallLogPop(1924);
6614  return true;
6615  }
6616  Utilities->CallLogPop(1925);
6617  return false;
6618 }
6619 
6620 // ---------------------------------------------------------------------------
6621 
6622 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
6623 {
6624 // return true for barrier in process of moving
6625  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6626  bool FoundFlag;
6627  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
6628 
6629  if(!FoundFlag)
6630  {
6631  Utilities->CallLogPop(1918);
6632  return false;
6633  }
6634  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6635  {
6636  Utilities->CallLogPop(1919);
6637  return false;
6638  }
6639  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
6640  {
6641  Utilities->CallLogPop(1920);
6642  return true;
6643  }
6644  Utilities->CallLogPop(1921);
6645  return false;
6646 }
6647 
6648 // ---------------------------------------------------------------------------
6649 
6650 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
6651 {
6652 // return true for an LC at H&V
6653  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6654  bool FoundFlag;
6655  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
6656 
6657  if(!FoundFlag)
6658  {
6659  Utilities->CallLogPop(1902);
6660  return false;
6661  }
6662  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6663  {
6664  Utilities->CallLogPop(1903);
6665  return false;
6666  }
6667  Utilities->CallLogPop(1904);
6668  return true;
6669 }
6670 
6671 // ---------------------------------------------------------------------------
6672 
6673 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
6674 {
6675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
6676  AnsiString(Attr));
6677  bool FoundFlag;
6678  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
6679 
6680  if(!FoundFlag)
6681  {
6682  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6683  }
6684  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
6685  {
6686  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
6687  }
6688  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
6689  Utilities->CallLogPop(1905);
6690  return;
6691 }
6692 
6693 // ---------------------------------------------------------------------------
6694 
6696 {
6697  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
6698  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
6699  {
6700  TTrackElement InactiveTrackElement = InactiveTrackVector.at(x);
6701  if(InactiveTrackElement.TrackType == LevelCrossing)
6702  {
6703  InactiveTrackVector.at(x).Attribute = 0;
6704  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
6705  }
6706  }
6707  Utilities->CallLogPop(1913);
6708  return;
6709 }
6710 
6711 // ---------------------------------------------------------------------------
6712 
6713 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
6714 {
6715 // return true if there is either a route set on any element or a train on any element
6716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
6717  "," + AnsiString(VLoc));
6718 
6719  THVPair TrackMapKeyPair;
6720  TTrack::TTrackMapIterator TrackMapPtr;
6721  int DummyRouteNumber;
6722 
6723  TrainPresent = false;
6724 // find topmost LC, checking each for routes & trains
6725  int UpStep = 0;
6726 
6727  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6728  {
6729  TrackMapKeyPair.first = HLoc;
6730  TrackMapKeyPair.second = VLoc + UpStep;
6731  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6732  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6733  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6734  {
6735  Utilities->CallLogPop(1932);
6736  return true;
6737  }
6738  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
6739  {
6740  TrainPresent = true;
6741  Utilities->CallLogPop(1933);
6742  return true;
6743  }
6744  UpStep--;
6745  }
6746 // now find bottommost LC, opening them all (to trains) in turn
6747  int DownStep = 1;
6748 
6749  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
6750  {
6751  TrackMapKeyPair.first = HLoc;
6752  TrackMapKeyPair.second = VLoc + DownStep;
6753  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6754  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6755  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6756  {
6757  Utilities->CallLogPop(1934);
6758  return true;
6759  }
6760  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
6761  {
6762  TrainPresent = true;
6763  Utilities->CallLogPop(1935);
6764  return true;
6765  }
6766  DownStep++;
6767  }
6768 // find leftmost LC
6769  int LeftStep = 0;
6770 
6771  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6772  {
6773  TrackMapKeyPair.first = HLoc + LeftStep;
6774  TrackMapKeyPair.second = VLoc;
6775  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6776  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6777  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6778  {
6779  Utilities->CallLogPop(1936);
6780  return true;
6781  }
6782  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
6783  {
6784  TrainPresent = true;
6785  Utilities->CallLogPop(1937);
6786  return true;
6787  }
6788  LeftStep--;
6789  }
6790 // now find rightmost LC, opening them all (to trains) in turn
6791  int RightStep = 1;
6792 
6793  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
6794  {
6795  TrackMapKeyPair.first = HLoc + RightStep;
6796  TrackMapKeyPair.second = VLoc;
6797  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6798  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
6799  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
6800  {
6801  Utilities->CallLogPop(1938);
6802  return true;
6803  }
6804  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
6805  {
6806  TrainPresent = true;
6807  Utilities->CallLogPop(1939);
6808  return true;
6809  }
6810  RightStep++;
6811  }
6812  Utilities->CallLogPop(1940);
6813  return false;
6814 }
6815 
6816 // ---------------------------------------------------------------------------
6817 
6818 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
6819 {
6820  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
6821  if(TrackElement.TrackType != Points)
6822  {
6823  throw Exception("Error, Wrong track type in GetFilletGraphic");
6824  }
6825  if(TrackElement.SpeedTag < 28)
6826  {
6827  Utilities->CallLogPop(521);
6828  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute];
6829  }
6830  else if(TrackElement.SpeedTag < 132)
6831  {
6832  Utilities->CallLogPop(522);
6833 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6834  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute];
6835  }
6836  else
6837  {
6838  Utilities->CallLogPop(1537);
6839  return RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute];
6840  }
6841 }
6842 
6843 // ---------------------------------------------------------------------------
6844 
6846 {
6847  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
6848  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
6849  {
6850  TrackVector.at(x).TrainIDOnElement = -1;
6851  TrackVector.at(x).TrainIDOnBridgeTrackPos01 = -1;
6852  TrackVector.at(x).TrainIDOnBridgeTrackPos23 = -1;
6853  }
6854  Utilities->CallLogPop(1342);
6855 }
6856 
6857 // ---------------------------------------------------------------------------
6858 
6859 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
6860 /*
6861  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
6862 */
6863 {
6864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6865  AnsiString(ScreenPosV));
6866  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
6867  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
6868 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
6869  Utilities->CallLogPop(535);
6870 }
6871 
6872 // ---------------------------------------------------------------------------
6873 
6874 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
6875 /*
6876  Converts the screen position to the true (without offsets) position
6877 */
6878 {
6879  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
6880  AnsiString(ScreenPosV));
6881  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
6882  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
6883  Utilities->CallLogPop(536);
6884 }
6885 
6886 // ---------------------------------------------------------------------------
6887 
6888 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
6889 {
6890  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
6891  AnsiString(VPosTrue));
6892  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
6893  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
6894  Utilities->CallLogPop(537);
6895 }
6896 
6897 // ---------------------------------------------------------------------------
6898 
6899 void TTrack::CheckMapAndTrack(int Caller) // test
6900 {
6901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
6902  int Zeroes = 0;
6903  bool FoundFlag;
6904 
6905  for(unsigned int a = 0; a < TrackVector.size(); a++)
6906  {
6907  TTrackElement CheckElement = Track->TrackVector.at(a);
6908  if(CheckElement.SpeedTag == 0)
6909  {
6910  Zeroes++; // zeroed elements not saved in map
6911  }
6912  else
6913  {
6914  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6915  if(!FoundFlag)
6916  {
6917  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6918  " in TrackMap, Caller=" + (AnsiString)Caller);
6919  }
6920  if(MapVecPos != (int)a)
6921  {
6922  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6923  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
6924  (AnsiString)Caller);
6925  }
6926  }
6927  }
6928  if(TrackVector.size() != (TrackMap.size() + Zeroes))
6929  {
6930  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6931  " Caller=" + (AnsiString)Caller);
6932  }
6933  Utilities->CallLogPop(538);
6934  return;
6935 }
6936 
6937 // ---------------------------------------------------------------------------
6938 
6939 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
6940 {
6941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
6942  bool FoundFlag;
6943  TIMPair InactivePair;
6944 
6945  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
6946  {
6947  TTrackElement CheckElement = Track->InactiveTrackVector.at(a);
6948  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
6949  if(!FoundFlag)
6950  {
6951  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
6952  " in InactiveMap, Caller=" + (AnsiString)Caller);
6953  }
6954  if((InactivePair.first != a) && (InactivePair.second != a))
6955  {
6956  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
6957  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
6958  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
6959  }
6960  }
6961  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
6962  {
6963  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
6964  " Caller=" + (AnsiString)Caller);
6965  }
6966  Utilities->CallLogPop(539);
6967 }
6968 
6969 // ---------------------------------------------------------------------------
6970 
6971 void TTrack::CheckGapMap(int Caller) // test
6972 {
6973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
6974  int Position1, Position2;
6975  TTrackElement TrackElement1, TrackElement2;
6976  TGapMapIterator GapMapPtr;
6977 
6978  if(!GapMap.empty())
6979  {
6980  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
6981  {
6982  int HLoc1 = GapMapPtr->first.first;
6983  int VLoc1 = GapMapPtr->first.second;
6984  int HLoc2 = GapMapPtr->second.first;
6985  int VLoc2 = GapMapPtr->second.second;
6986  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
6987  {
6988  throw Exception("Failed to find H & V for gap1, GapMap in error");
6989  }
6990  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
6991  {
6992  throw Exception("Failed to find H & V for gap2, GapMap in error");
6993  }
6994  if(TrackElementAt(17, Position1).TrackType != GapJump)
6995  {
6996  throw Exception("Element at Pos1 not a gap, GapMap in error");
6997  }
6998  if(TrackElementAt(18, Position2).TrackType != GapJump)
6999  {
7000  throw Exception("Element at Pos2 not a gap, GapMap in error");
7001  }
7002  }
7003  }
7004  unsigned int GapCount = 0;
7005 
7006  for(unsigned int a = 0; a < TrackVector.size(); a++)
7007  {
7008  TTrackElement CheckElement = Track->TrackVector.at(a);
7009  if(CheckElement.TrackType == GapJump)
7010  GapCount++;
7011  }
7012  if((GapMap.size() * 2) != GapCount)
7013  {
7014  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7015  (AnsiString)Caller);
7016  }
7017  Utilities->CallLogPop(540);
7018 }
7019 
7020 // ---------------------------------------------------------------------------
7021 
7022 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7023 {
7024  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7025  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7026  {
7027  if(TrackFinished)
7028  {
7029  throw Exception("Error - TrackFinished with erase element still present");
7030  }
7031  Utilities->CallLogPop(541);
7032  return; // erased element, can't set ID
7033  }
7034  AnsiString IDString;
7035 
7036  if(TrackElement.HLoc < 0)
7037  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7038  else
7039  IDString = AnsiString(TrackElement.HLoc) + "-";
7040  if(TrackElement.VLoc < 0)
7041  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7042  else
7043  IDString += AnsiString(TrackElement.VLoc);
7044  TrackElement.ElementID = IDString;
7045  Utilities->CallLogPop(542);
7046 }
7047 
7048 // ---------------------------------------------------------------------------
7049 
7050 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7051 {
7052 // e.g. "8-13", "00008-13", "N43-N127", etc
7053  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7054  int DelimPos;
7055 
7056  for(int x = 1; x < String.Length() + 1; x++)
7057  {
7058  if(String.IsDelimiter("-", x))
7059  {
7060  DelimPos = x;
7061  break;
7062  }
7063  if(x == String.Length())
7064  {
7065  if(GiveMessages)
7066  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7067  Utilities->CallLogPop(543);
7068  return -1;
7069  }
7070  }
7071  if(DelimPos == 1)
7072  {
7073  if(GiveMessages)
7074  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7075  Utilities->CallLogPop(544);
7076  return -1;
7077  }
7078  if(DelimPos == String.Length())
7079  {
7080  if(GiveMessages)
7081  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7082  Utilities->CallLogPop(545);
7083  return -1;
7084  }
7085  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7086  {
7087  if(GiveMessages)
7088  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7089  Utilities->CallLogPop(1508);
7090  return -1;
7091  }
7092  int HLoc, VLoc;
7093 
7094  if(String.SubString(1, 1) != "N")
7095  {
7096  for(int x = 1; x < DelimPos; x++)
7097  {
7098  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7099  {
7100  if(GiveMessages)
7101  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7102  Utilities->CallLogPop(546);
7103  return -1;
7104  }
7105  }
7106  }
7107  if(String.SubString(1, 1) == "N")
7108  {
7109  for(int x = 2; x < DelimPos; x++)
7110  {
7111  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7112  {
7113  if(GiveMessages)
7114  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7115  Utilities->CallLogPop(763);
7116  return -1;
7117  }
7118  }
7119  }
7120  if(String.SubString(1, 1) == "N")
7121  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7122  else
7123  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7124 
7125  if(String.SubString(DelimPos + 1, 1) != "N")
7126  {
7127  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7128  {
7129  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7130  {
7131  if(GiveMessages)
7132  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7133  Utilities->CallLogPop(547);
7134  return -1;
7135  }
7136  }
7137  }
7138  if(String.SubString(DelimPos + 1, 1) == "N")
7139  {
7140  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7141  {
7142  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7143  {
7144  if(GiveMessages)
7145  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7146  Utilities->CallLogPop(764);
7147  return -1;
7148  }
7149  }
7150  }
7151  if(String.SubString(DelimPos + 1, 1) == "N")
7152  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7153  else
7154  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7155 
7156  THVPair HVPair(HLoc, VLoc);
7157  TTrackMapIterator TrackMapPtr;
7158 
7159  TrackMapPtr = TrackMap.find(HVPair);
7160  if(TrackMapPtr == TrackMap.end())
7161  {
7162  if(GiveMessages)
7163  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7164  Utilities->CallLogPop(548);
7165  return -1;
7166  }
7167  Utilities->CallLogPop(549);
7168  return TrackMapPtr->second;
7169 }
7170 
7171 // ---------------------------------------------------------------------------
7172 
7173 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7174 /*
7175  True for linked properly at both ends
7176 */
7177 {
7178  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7179  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7180  int HLoc = TrackElement.HLoc;
7181  int VLoc = TrackElement.VLoc;
7182 
7183  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7184  {
7185  Utilities->CallLogPop(1821);
7186  return false;
7187  }
7188  if(TrackElement.SpeedTag == 129) // vertical footbridge
7189  {
7190  // check top connection
7191  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7192  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7193  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7194  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7195  {
7196  Utilities->CallLogPop(550);
7197  return false;
7198  }
7199  // check bottom connection
7200  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7201  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7202  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7203  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
7204  {
7205  Utilities->CallLogPop(551);
7206  return false;
7207  }
7208  }
7209  if(TrackElement.SpeedTag == 145) // vertical underpass
7210  {
7211  // check top connection
7212  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
7213  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
7214  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
7215  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
7216  {
7217  Utilities->CallLogPop(2114);
7218  return false;
7219  }
7220  // check bottom connection
7221  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
7222  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
7223  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
7224  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
7225  {
7226  Utilities->CallLogPop(2115);
7227  return false;
7228  }
7229  }
7230  if(TrackElement.SpeedTag == 130) // hor footbridge
7231  {
7232  // check left connection
7233  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
7234  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
7235  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
7236  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
7237  {
7238  Utilities->CallLogPop(552);
7239  return false;
7240  }
7241  // check right connection
7242  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
7243  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
7244  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
7245  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
7246  {
7247  Utilities->CallLogPop(553);
7248  return false;
7249  }
7250  }
7251  if(TrackElement.SpeedTag == 146) // hor u'pass
7252  {
7253  // check left connection
7254  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
7255  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
7256  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
7257  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
7258  {
7259  Utilities->CallLogPop(2116);
7260  return false;
7261  }
7262  // check right connection
7263  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
7264  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
7265  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
7266  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
7267  {
7268  Utilities->CallLogPop(2117);
7269  return false;
7270  }
7271  }
7272  Utilities->CallLogPop(554);
7273  return true;
7274 }
7275 
7276 // ---------------------------------------------------------------------------
7277 
7278 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7279 /*
7280  return true if the SpeedTag present in the map at H & V
7281 */
7282 {
7283  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7284  AnsiString(SpeedTag));
7285  if(InactiveTrack2MultiMap.empty())
7286  {
7287  Utilities->CallLogPop(555);
7288  return false;
7289  }
7290  THVPair HVPair(HLoc, VLoc);
7292  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
7293  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
7294 
7295  if(HVRange.first == HVRange.second)
7296  {
7297  Utilities->CallLogPop(556);
7298  return false;
7299  }
7300  else
7301  HVIt1 = HVRange.first;
7302  TTrackElement Temp1, Temp2; // test
7303 
7304  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
7305  if(--HVRange.second != HVRange.first)
7306  {
7307  HVIt2 = HVRange.second;
7308  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
7309  }
7310  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
7311  HVIt2->second).SpeedTag == SpeedTag)))
7312  {
7313  Utilities->CallLogPop(557);
7314  return true;
7315  }
7316  else
7317  {
7318  Utilities->CallLogPop(558);
7319  return false;
7320  }
7321 }
7322 
7323 // ---------------------------------------------------------------------------
7324 
7325 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7326 /*
7327  return true if the SpeedTag present in the map at H & V
7328 */
7329 {
7330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7331  AnsiString(SpeedTag));
7332  if(TrackMap.empty())
7333  {
7334  Utilities->CallLogPop(559);
7335  return false;
7336  }
7337  THVPair HVPair(HLoc, VLoc);
7338  TTrackMapIterator End = TrackMap.end();
7339  TTrackMapIterator It = End;
7340 
7341  It = TrackMap.find(HVPair);
7342  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
7343  {
7344  Utilities->CallLogPop(560);
7345  return true;
7346  }
7347  else
7348  {
7349  Utilities->CallLogPop(561);
7350  return false;
7351  }
7352 }
7353 
7354 // ---------------------------------------------------------------------------
7355 
7356 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
7357 {
7358 /*
7359  General:
7360  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
7361  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
7362  a NamedNonStationLocation.
7363  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
7364  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
7365  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
7366  platform at that location).
7367 
7368  Linked named location elements are those explained in TTrack::TTrack()
7369 
7370  Detail:
7371  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
7372  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
7373  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
7374  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
7375  work OK! e.g. vector position 0 would be stored as -1, position n would be stored as -1-n. To recover the true position
7376  from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
7377 
7378  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
7379  this function a single element should be in the List (normally from the user's selection but can also be from
7380  SearchForAndUpdateLocationName), and the Map is cleared within the function.
7381  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
7382  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
7383  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
7384  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
7385  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
7386  moves them into the Map. At the end all linked elements are in the Map.
7387 
7388  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
7389  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
7390  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
7391 */
7392 
7393 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
7394 // Display->FileDiagnostics(TestString);//test
7395 
7396  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
7397  AnsiString TestString1, TestString2; // test
7398 
7399  Track->LNDone2MultiMap.clear();
7400  if(LNPendingList.size() != 1)
7401  {
7402  throw Exception("LNPendingList size not 1 on entry");
7403  }
7404  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
7405  while(!LNPendingList.empty())
7406  {
7407  CurrentElementNumber = LNPendingList.front();
7408  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
7409  int NewElement; // = 2000000000; //marker for unused //not needed after v1.1.4
7410  int H = CurrentElement->HLoc;
7411  int V = CurrentElement->VLoc;
7412  int Tag = CurrentElement->SpeedTag;
7413  if(Tag == 76) // top plat
7414  {
7415  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
7416  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
7417  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
7418  for(int x = 0; x < 25; x++)
7419  {
7420  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
7421  {
7422  LNPendingList.insert(LNPendingList.end(), NewElement);
7423  }
7424  }
7425  }
7426  else if(Tag == 77) // bot plat
7427  {
7428  for(int x = 0; x < 25; x++)
7429  {
7430  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
7431  {
7432  LNPendingList.insert(LNPendingList.end(), NewElement);
7433  }
7434  }
7435  }
7436  else if(Tag == 78) // l plat
7437  {
7438  for(int x = 0; x < 25; x++)
7439  {
7440  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
7441  {
7442  LNPendingList.insert(LNPendingList.end(), NewElement);
7443  }
7444  }
7445  }
7446  else if(Tag == 79) // r plat
7447  {
7448  for(int x = 0; x < 25; x++)
7449  {
7450  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
7451  {
7452  LNPendingList.insert(LNPendingList.end(), NewElement);
7453  }
7454  }
7455  }
7456  else if(Tag == 96) // conc
7457  {
7458  for(int x = 0; x < 28; x++)
7459  {
7460  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
7461  {
7462  LNPendingList.insert(LNPendingList.end(), NewElement);
7463  }
7464  }
7465  }
7466  else if(Tag == 129) // vert footbridge
7467  {
7468  for(int x = 0; x < 8; x++)
7469  {
7470  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
7471  {
7472  LNPendingList.insert(LNPendingList.end(), NewElement);
7473  }
7474  }
7475  }
7476  else if(Tag == 130) // hor footbridge
7477  {
7478  for(int x = 0; x < 8; x++)
7479  {
7480  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
7481  {
7482  LNPendingList.insert(LNPendingList.end(), NewElement);
7483  }
7484  }
7485  }
7486  else if(Tag == 131) // named location
7487  {
7488  for(int x = 0; x < 4; x++)
7489  {
7490  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
7491  {
7492  LNPendingList.insert(LNPendingList.end(), NewElement);
7493  }
7494  }
7495  }
7496  else if(Tag == 145) // v u'pass
7497  {
7498  for(int x = 0; x < 8; x++)
7499  {
7500  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
7501  {
7502  LNPendingList.insert(LNPendingList.end(), NewElement);
7503  }
7504  }
7505  }
7506  else if(Tag == 146) // h u'pass
7507  {
7508  for(int x = 0; x < 8; x++)
7509  {
7510  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
7511  {
7512  LNPendingList.insert(LNPendingList.end(), NewElement);
7513  }
7514  }
7515  }
7516  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
7517 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
7518  if(AddingElements)
7519  {
7520  int HPos, VPos; // not used but needed for FindText function
7521  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
7522  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
7523  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
7524  {
7525  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName;//existing name of CurrentElement
7526  if((ExistingName != "") && (ExistingName != LocationName))
7527  {
7528  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
7529  {} // name not in LocationNameMultiMap, so don't erase from TextVector
7530  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
7531  {
7532  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
7533  {;
7534  } // condition not used
7535  }
7536  }
7537  }
7538  }
7539 
7540  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
7541  // track at that loc
7542  THVPair HVPair(H, V);
7543  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
7544  LNDone2MultiMapEntry.first = HVPair;
7545  LNDone2MultiMapEntry.second = LNPendingList.front();
7546  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
7547  LNPendingList.erase(LNPendingList.begin());
7548  }
7549 
7550 // search all name multimap for same name where corresponding active elements don't appear in
7551 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
7552 
7553  TLocationNameMultiMapIterator SNIterator;
7554  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7555  bool FoundFlag, ErasedFlag = false;
7556 
7557  if(SNRange.first != SNRange.second)
7558  {
7559  SNRange.first--; // now pointing to before the first
7560  SNRange.second--; // now pointing to the last
7561  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
7562  // Same elements are in Done map as in name map
7563  {
7564  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
7565  {
7566  ErasedFlag = true;
7567  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
7568  TVIt->LocationName = "";
7569  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
7570  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
7571  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
7572  {
7573  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
7574  if(FoundFlag)
7575  {
7576  TrackElementAt(20, Position).LocationName = "";
7577  TrackElementAt(21, Position).ActiveTrackElementName = "";
7578  }
7579  }
7580  // erase name in name map
7581 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
7582  }
7583  }
7584  }
7585  if(ErasedFlag)
7587  if(TrackFinished)
7589 // set here as well as in LinkTrack so don't have to link track just because a name added
7590 // if track not finished then will be set when track validated
7591  CheckLocationNameMultiMap(1); // test
7592  Utilities->CallLogPop(562);
7593 }
7594 
7595 // ---------------------------------------------------------------------------
7596 
7597 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
7598 /*
7599  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
7600  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
7601 */
7602 {
7603  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7604  AnsiString(SpeedTag));
7605  if(!NamedLocationElementAt(2, HLoc, VLoc))
7606  {
7607  Utilities->CallLogPop(948);
7608  return false;
7609  }
7610  bool FoundFlag;
7611  int Position = -1;
7612  TIMPair IMPair;
7613 
7614  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
7615  {
7616  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
7617  if(FoundFlag)
7618  {
7619  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
7620  {
7621  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
7622  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
7623  // don't allow duplicates in either list, or processing takes a lot longer
7624  {
7625  FoundElement = MapPos;
7626  Utilities->CallLogPop(563);
7627  return true;
7628  }
7629  }
7630  }
7631  }
7632  else
7633  {
7634  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
7635  if(FoundFlag)
7636  {
7637  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
7638  {
7639  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
7640  {
7641  FoundElement = IMPair.first;
7642  Utilities->CallLogPop(564);
7643  return true;
7644  }
7645  }
7646  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
7647  {
7648  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
7649  {
7650  FoundElement = IMPair.second;
7651  Utilities->CallLogPop(565);
7652  return true;
7653  }
7654  }
7655  }
7656  }
7657  Utilities->CallLogPop(566);
7658  return false;
7659 }
7660 
7661 // ---------------------------------------------------------------------------
7662 
7663 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
7664 /*
7665  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
7666  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
7667  with the new name
7668 */
7669 {
7670  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
7671  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
7672 
7673  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
7674  int HLoc = TrackElement->HLoc;
7675  int VLoc = TrackElement->VLoc;
7676  bool FoundFlag;
7677 
7678  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
7679  // only have timetable names for adjacent platforms & named locations
7680  {
7681  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
7682  if(FoundFlag)
7683  {
7684  TrackElementAt(23, Position).ActiveTrackElementName = Name;
7685  }
7686  }
7687  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
7688 
7689  if(ErrorString != "")
7690  {
7691  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
7692  }
7693  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
7694  CheckLocationNameMultiMap(2); // test
7695  Utilities->CallLogPop(567);
7696 }
7697 
7698 // ---------------------------------------------------------------------------
7699 
7700 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
7701 /*
7702  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
7703 */
7704 {
7705  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
7706  if(LNDone2MultiMap.empty())
7707  {
7708  Utilities->CallLogPop(568);
7709  return false;
7710  }
7711  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
7712 
7713  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
7714  {
7715  if(LNDone2MultiMapIterator->second == MapPos)
7716  {
7717  Utilities->CallLogPop(569);
7718  return true;
7719  }
7720  }
7721  Utilities->CallLogPop(570);
7722  return false;
7723 }
7724 
7725 // ---------------------------------------------------------------------------
7726 
7727 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
7728 /*
7729  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
7730 */
7731 {
7732  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
7733  if(LNPendingList.empty())
7734  {
7735  Utilities->CallLogPop(571);
7736  return false;
7737  }
7738  TLNPendingListIterator LNPendingListIterator;
7739 
7740  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
7741  {
7742  if(*LNPendingListIterator == MapPos)
7743  {
7744  Utilities->CallLogPop(572);
7745  return true;
7746  }
7747  }
7748  Utilities->CallLogPop(573);
7749  return false;
7750 }
7751 
7752 // ---------------------------------------------------------------------------
7753 
7754 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
7755 /*
7756  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
7757 */
7758 {
7759  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7760  THVPair HVPair(HLoc, VLoc);
7761  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
7762  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
7763 
7764  if(TrackMapPtr != TrackMap.end()) // =end() if not found
7765  {
7766  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
7767  {
7768  Utilities->CallLogPop(574);
7769  return true;
7770  }
7771  }
7772  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
7773  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
7774  {
7775  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
7776  {
7777  Utilities->CallLogPop(575);
7778  return true;
7779  }
7780  }
7781  Utilities->CallLogPop(576);
7782  return false;
7783 }
7784 
7785 // ---------------------------------------------------------------------------
7786 
7787 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
7788 {
7789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
7790  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
7791  {
7792  Utilities->CallLogPop(1953);
7793  return true;
7794  }
7795  Utilities->CallLogPop(1954);
7796  return false;
7797 }
7798 
7799 // ---------------------------------------------------------------------------
7800 
7801 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
7802 /*
7803  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
7804 */
7805 
7806 {
7807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
7808  if(LocationName == "")
7809  {
7810  Utilities->CallLogPop(577);
7811  return false;
7812  }
7813 // new for v0.2b
7814 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
7816  {
7817  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
7818  ActiveTrackElementNameMap.clear();
7819  for(unsigned int x = 0; x < TrackVector.size(); x++)
7820  {
7821  if((TrackVector.at(x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackVector.at(x).ActiveTrackElementName))
7822  == ContinuationNameMap.end())
7823  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
7824  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
7825  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
7826  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
7827  }
7828  }
7830  }
7831  Utilities->CallLogPop(578);
7832  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
7833 // end of new section
7834 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
7835 }
7836 
7837 // ---------------------------------------------------------------------------
7838 
7839 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
7840 /*
7841  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
7842  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
7843  new names in the vectors.
7844 */
7845 {
7846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
7847  bool FoundFlag, ErasedFlag = false;
7848  TLocationNameMultiMapIterator SNIterator;
7849  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
7850 
7851  if(SNRange.first != SNRange.second)
7852  {
7853  ErasedFlag = true;
7854  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
7855  {
7856  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
7857  TVIt->LocationName = "";
7858  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
7859  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
7860  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
7861  {
7862  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
7863  if(FoundFlag)
7864  {
7865  TrackElementAt(25, Position).LocationName = "";
7866  TrackElementAt(26, Position).ActiveTrackElementName = "";
7867  }
7868  }
7869  }
7870  }
7871  if(ErasedFlag)
7873  CheckLocationNameMultiMap(3); // test
7874  Utilities->CallLogPop(579);
7875 }
7876 
7877 // ---------------------------------------------------------------------------
7878 
7879 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
7880 /*
7881  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
7882  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
7883  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
7884  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
7885  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
7886  naming up to date with the deletion or insertion.
7887 */
7888 {
7889  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
7890  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
7891  LNPendingList.clear();
7892  AnsiString LocationName;
7893  int MapPos;
7894  bool FoundFlag = 0;
7895 
7896 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
7897  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
7898  if(FoundFlag)
7899  {
7900  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
7901  if(LocationName != "")
7902  {
7903  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
7904  EnterLocationName(13, LocationName, true);
7905  Utilities->CallLogPop(2251);
7906  return;
7907  }
7908  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
7909  if(LocationName != "")
7910  {
7911  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
7912  EnterLocationName(14, LocationName, true);
7913  Utilities->CallLogPop(2252);
7914  return;
7915  }
7916  }
7917 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
7918 
7919  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
7920  if(FoundFlag)
7921  {
7922  LocationName = TrackElementAt(1004, Position).LocationName;
7923  if(LocationName != "")
7924  {
7925  int ModifiedPosition = -1 - Position;
7926  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
7927  EnterLocationName(15, LocationName, true);
7928  Utilities->CallLogPop(2253);
7929  return;
7930  }
7931  }
7932 
7933  if(SpeedTag == 76) // top plat
7934  {
7935  for(int x = 0; x < 25; x++)
7936  {
7937  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
7938  {
7939  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7940  EnterLocationName(3, LocationName, true);
7941  break;
7942  }
7943  }
7944  }
7945  else if(SpeedTag == 77) // bot plat
7946  {
7947  for(int x = 0; x < 25; x++)
7948  {
7949  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
7950  {
7951  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7952  EnterLocationName(4, LocationName, true);
7953  break;
7954  }
7955  }
7956  }
7957  else if(SpeedTag == 78) // l plat
7958  {
7959  for(int x = 0; x < 25; x++)
7960  {
7961  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
7962  {
7963  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7964  EnterLocationName(5, LocationName, true);
7965  break;
7966  }
7967  }
7968  }
7969  else if(SpeedTag == 79) // r plat
7970  {
7971  for(int x = 0; x < 25; x++)
7972  {
7973  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
7974  {
7975  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7976  EnterLocationName(6, LocationName, true);
7977  break;
7978  }
7979  }
7980  }
7981  else if(SpeedTag == 96) // conc
7982  {
7983  for(int x = 0; x < 28; x++)
7984  {
7985  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
7986  {
7987  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
7988  EnterLocationName(7, LocationName, true);
7989  break;
7990  }
7991  }
7992  }
7993  else if(SpeedTag == 129) // vert footbridge
7994  {
7995  for(int x = 0; x < 8; x++)
7996  {
7997  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
7998  {
7999  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8000  EnterLocationName(8, LocationName, true);
8001  break;
8002  }
8003  }
8004  }
8005  else if(SpeedTag == 130) // hor footbridge
8006  {
8007  for(int x = 0; x < 8; x++)
8008  {
8009  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8010  {
8011  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8012  EnterLocationName(9, LocationName, true);
8013  break;
8014  }
8015  }
8016  }
8017  else if(SpeedTag == 145) // vert u'pass
8018  {
8019  for(int x = 0; x < 8; x++)
8020  {
8021  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8022  {
8023  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8024  EnterLocationName(11, LocationName, true);
8025  break;
8026  }
8027  }
8028  }
8029  else if(SpeedTag == 146) // hor u'pass
8030  {
8031  for(int x = 0; x < 8; x++)
8032  {
8033  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
8034  {
8035  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8036  EnterLocationName(12, LocationName, true);
8037  break;
8038  }
8039  }
8040  }
8041  else if(SpeedTag == 131) // named location
8042  {
8043  for(int x = 0; x < 4; x++)
8044  {
8045  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
8046  {
8047  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8048  EnterLocationName(10, LocationName, true);
8049  break;
8050  }
8051  }
8052  }
8053 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
8054  Utilities->CallLogPop(580);
8055 }
8056 
8057 // ---------------------------------------------------------------------------
8058 
8059 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
8060 /*
8061  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
8062  true if a LocationName is found, and also returns the name and the adjusted vector position.
8063 */
8064 {
8065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8066  AnsiString(SpeedTag));
8067  bool FoundFlag;
8068  TIMPair IMPair;
8069  TTrackVectorIterator TempElement;
8070  int Position;
8071 
8072  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
8073  if(FoundFlag)
8074  {
8075  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
8076  {
8077  TempElement = InactiveTrackVector.begin() + IMPair.first;
8078  if(TempElement->LocationName != "")
8079  {
8080  LocationName = TempElement->LocationName;
8081  FoundElement = IMPair.first;
8082  Utilities->CallLogPop(581);
8083  return true;
8084  }
8085  }
8086  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
8087  {
8088  TempElement = InactiveTrackVector.begin() + IMPair.second;
8089  if(TempElement->LocationName != "")
8090  {
8091  LocationName = TempElement->LocationName;
8092  FoundElement = IMPair.second;
8093  Utilities->CallLogPop(582);
8094  return true;
8095  }
8096  }
8097  }
8098 
8099  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
8100  if(FoundFlag)
8101  {
8102  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
8103  {
8104  TempElement = TrackVector.begin() + Position;
8105  if(TempElement->LocationName != "")
8106  {
8107  LocationName = TempElement->LocationName;
8108  FoundElement = -1 - Position;
8109  Utilities->CallLogPop(583);
8110  return true;
8111  }
8112  }
8113  }
8114  Utilities->CallLogPop(584);
8115  return false;
8116 }
8117 
8118 // ---------------------------------------------------------------------------
8119 
8120 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
8121 {
8122 // check quantity in map & vectors match
8123  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
8124  unsigned int Count = 0;
8125 
8126  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
8127  {
8128  Utilities->CallLogPop(2059);
8129  return;
8130  }
8131 
8132  AnsiString SName, TName, ErrorString;
8133 
8134  for(unsigned int x = 0; x < TrackVector.size(); x++)
8135  {
8136  if(TrackVector.at(x).FixedNamedLocationElement)
8137  {
8138  if(TrackVector.at(x).TrackType != FootCrossing)
8139  {
8140  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
8141  AnsiString(Caller));
8142  }
8143  Count++;
8144  }
8145  }
8146  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8147  {
8148  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8149  {
8150  if((InactiveTrackVector.at(x).TrackType != Platform) && (InactiveTrackVector.at(x).TrackType != NamedNonStationLocation) &&
8151  (InactiveTrackVector.at(x).TrackType != Concourse))
8152  {
8153  throw Exception
8154  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
8155  AnsiString(Caller));
8156  }
8157  Count++;
8158  }
8159  }
8160  if(LocationNameMultiMap.size() != Count)
8161  {
8162  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
8163  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8164  }
8165 
8166 // check all entries in both vectors match entries in name multimap
8168 
8169  for(unsigned int x = 0; x < TrackVector.size(); x++)
8170  {
8171  if(TrackVector.at(x).FixedNamedLocationElement)
8172  {
8173  SName = TrackVector.at(x).LocationName;
8174  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
8175  if(ErrorString != "")
8176  {
8177  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
8178  }
8179  if(SNIt->second != -1 - (int)x)
8180  {
8181  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8182  AnsiString(Caller));
8183  }
8184  }
8185  // check corresponding platform for all Timetable entries that aren't empty
8186  TName = TrackVector.at(x).ActiveTrackElementName;
8187  TIMPair IMPair;
8188  bool FoundFlag = false;
8189  if(TName != "")
8190  {
8191  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc, FoundFlag);
8192  if(FoundFlag)
8193  {
8194  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
8196  {
8197  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8198  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8199  }
8200  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
8201  {
8202  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) +
8203  " & V " + AnsiString(TrackVector.at(x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
8204  AnsiString(Caller));
8205  }
8206  }
8207  else
8208  {
8209  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8210  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8211  }
8212  }
8213  }
8214  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8215  {
8216  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8217  {
8218  SName = InactiveTrackVector.at(x).LocationName;
8219  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
8220  if(ErrorString != "")
8221  {
8222  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
8223  }
8224  if(SNIt->second != (int)x)
8225  {
8226  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8227  AnsiString(Caller));
8228  }
8229  }
8230  }
8231  Utilities->CallLogPop(585);
8232 }
8233 
8234 // ---------------------------------------------------------------------------
8235 
8237  AnsiString &ErrorString)
8238 {
8239 /*
8240  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
8241  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
8242  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
8243 */
8244  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
8245  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
8246  ErrorString = "";
8247  bool FoundFlag = false;
8248  TLocationNameMultiMapIterator SNIterator;
8249  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8250 
8251  if(SNRange.first == SNRange.second)
8252  {
8253  ErrorString = "Error, Name " + LocationName + " not found in map";
8254  Utilities->CallLogPop(586);
8255  return SNRange.first;
8256  }
8257  else
8258  {
8259  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8260  {
8261  if(SNIterator->second < 0)
8262  {
8263  int TVPos = -1 - SNIterator->second;
8264  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
8265  if(TVIt == TrackElement)
8266  {
8267  FoundFlag = true;
8268  Utilities->CallLogPop(587);
8269  return SNIterator;
8270  }
8271  }
8272  else
8273  {
8274  int ITVPos = SNIterator->second;
8275  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
8276  if(ITVIt == TrackElement)
8277  {
8278  FoundFlag = true;
8279  Utilities->CallLogPop(588);
8280  return SNIterator;
8281  }
8282  }
8283  }
8284  }
8285  if(!FoundFlag)
8286  ErrorString = "Error, Name " + LocationName + " found but not at required element";
8287  Utilities->CallLogPop(589);
8288  return SNIterator;
8289 }
8290 
8291 // ---------------------------------------------------------------------------
8292 
8293 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
8294 {
8295 /*
8296  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
8297  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
8298 */
8299  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
8300  TLocationNameMultiMapEntry LocationNameEntry;
8301 
8302  LocationNameEntry.first = NewName;
8303  LocationNameEntry.second = SNIterator->second;
8304  LocationNameMultiMap.erase(SNIterator);
8305  LocationNameMultiMap.insert(LocationNameEntry);
8306  Utilities->CallLogPop(590);
8307 }
8308 
8309 // ---------------------------------------------------------------------------
8310 
8312 {
8313 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
8314  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
8315  if(Position < 0) // footcrossing
8316  {
8317  int TruePos = -1 - Position;
8318  // new check at v0.2b
8319  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
8320  {
8321  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
8322  }
8323  Utilities->CallLogPop(591);
8324  return (TrackVector.begin() + TruePos);
8325  }
8326  else
8327  {
8328  // new check at v0.2b
8329  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
8330  {
8331  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
8332  }
8333  Utilities->CallLogPop(592);
8334  return (InactiveTrackVector.begin() + Position);
8335  }
8336 }
8337 
8338 // ---------------------------------------------------------------------------
8339 
8340 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
8341 {
8342 /*
8343  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
8344  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
8345  LocationNameMultiMap.
8346 */
8347  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
8348  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
8349  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
8350 
8351  if(!InactiveTrack2MultiMap.empty())
8352  {
8353  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
8354  InactiveTrack2MultiMapIterator++)
8355  {
8356  if(InactiveTrack2MultiMapIterator->second > VecPos)
8357  InactiveTrack2MultiMapIterator->second--;
8358  // can't be == VecPos as that position erased
8359  }
8360  }
8361  if(!LocationNameMultiMap.empty())
8362  {
8363  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
8364  LocationNameMultiMapIterator++)
8365  {
8366  if(LocationNameMultiMapIterator->second < 0)
8367  continue; // deal with TrackVectors separately
8368  if(LocationNameMultiMapIterator->second > (int)VecPos)
8369  LocationNameMultiMapIterator->second--;
8370  }
8371  }
8372  Utilities->CallLogPop(593);
8373 }
8374 
8375 // ---------------------------------------------------------------------------
8376 
8377 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
8378 {
8379 /*
8380  After an element has been erased from the track vector, all the later elements are moved down one. This function
8381  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
8382  LocationNameMultiMap.
8383 */
8384  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
8385  TTrackMapIterator TrackMapIterator;
8386  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
8387 
8388  if(!TrackMap.empty())
8389  {
8390  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
8391  {
8392  if(TrackMapIterator->second > VecPos)
8393  TrackMapIterator->second--;
8394  // can't be == VecPos as that position erased
8395  }
8396  }
8397  if(!LocationNameMultiMap.empty())
8398  {
8399  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
8400  LocationNameMultiMapIterator++)
8401  {
8402  if(LocationNameMultiMapIterator->second >= 0)
8403  continue; // deal with InactiveTrackVectors separately
8404  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
8405  // Val -1 -2 -3 -4 -5 -6 -7 -8
8406  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
8407  LocationNameMultiMapIterator->second++;
8408  }
8409  }
8410  for(unsigned int x = 0; x < TrackVector.size(); x++)
8411  {
8412  TTrackElement &TkEl = TrackVector.at(x); // no need to check so use this to speed up
8413  if(TkEl.TrackType == GapJump)
8414  {
8415  // position 0 is the gap
8416  if(TkEl.Conn[0] == int(VecPos))
8417  {
8418  TkEl.Conn[0] = -1; // connected to a deleted gap
8419  continue;
8420  }
8421  if(TkEl.Conn[0] > int(VecPos))
8422  TkEl.Conn[0]--;
8423  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
8424  {
8425  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
8426  TkEl.Conn[0] = -1;
8427  }
8428  }
8429  }
8430  Utilities->CallLogPop(1433);
8431 }
8432 
8433 // ---------------------------------------------------------------------------
8434 
8436 /*
8437  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
8438  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
8439  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
8440 */
8441 {
8442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
8443  LocationNameMultiMap.clear();
8444  TLocationNameMultiMapEntry LocationNameEntry;
8445  TTrackElement TrackElement;
8446 
8447  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
8448  {
8449  TrackElement = TrackVector.at(TVPos);
8450  if(TrackElement.FixedNamedLocationElement)
8451  {
8452  LocationNameEntry.first = TrackElement.LocationName;
8453  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
8454  LocationNameMultiMap.insert(LocationNameEntry);
8455  }
8456  }
8457 
8458  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
8459  {
8460  TrackElement = InactiveTrackVector.at(ITVPos);
8461  if(TrackElement.FixedNamedLocationElement)
8462  {
8463  LocationNameEntry.first = TrackElement.LocationName;
8464  LocationNameEntry.second = ITVPos;
8465  LocationNameMultiMap.insert(LocationNameEntry);
8466  }
8467  }
8468  Utilities->CallLogPop(594);
8469 }
8470 
8471 // ---------------------------------------------------------------------------
8472 
8474  // Return true if there is a named location present in the railway
8475  // ignores lone footcrossings, can't name these on their own & track won't link if there are any
8476 {
8477  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
8478  TTrackVectorIterator ITVI;
8479 
8480  if(InactiveTrackVector.empty())
8481  {
8482  Utilities->CallLogPop(1343);
8483  return false;
8484  }
8485  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
8486  {
8487  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
8488  {
8489  Utilities->CallLogPop(1404);
8490  return true;
8491  }
8492  }
8493  Utilities->CallLogPop(1344);
8494  return false;
8495 }
8496 
8497 // ---------------------------------------------------------------------------
8498 
8500 /*
8501  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
8502 */
8503 {
8504  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
8505 // ResetDistanceElements(6);
8506  for(unsigned int x = 0; x < TrackVector.size(); x++)
8507  {
8508  TTrackElement &TE = TrackElementAt(718, x);
8511  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
8512  {
8515  }
8516  }
8517 /* old function
8518  if((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == Crossover) || (TrackVector.at(x).TrackType == Bridge))
8519  {
8520  SetOneDefaultTrackLength(2, TrackVector.at(x), 0);
8521  SetOneDefaultTrackLength(3, TrackVector.at(x), 2);
8522  }
8523  else
8524  {
8525  SetOneDefaultTrackLength(4, TrackVector.at(x), 0);
8526  }
8527  }
8528 */
8529  Utilities->CallLogPop(617);
8530 }
8531 
8532 // ---------------------------------------------------------------------------
8533 
8534 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
8535  // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
8536 {
8537  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
8538  for(unsigned int x = 0; x < TrackVector.size(); x++)
8539  {
8540  TTrackElement TempElement = TrackVector.at(x);
8541  if(TempElement.Length01 > -1)
8542  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
8543  if(TempElement.Length23 > -1)
8544  MarkOneLength(2, TempElement, false, Disp);
8545  }
8546  Disp->Update();
8547  Utilities->CallLogPop(618);
8548 }
8549 
8550 // ---------------------------------------------------------------------------
8551 
8552 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
8553 /*
8554  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
8555  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
8556  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
8557  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
8558  track as indicated by FirstTrack (true for track01 & false for track23).
8559 */
8560 {
8561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
8562  AnsiString((short)FirstTrack));
8563  bool LengthDifferent = false, SpeedDifferent = false;
8564 
8565  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
8566  {
8567  Utilities->CallLogPop(619);
8568  return;
8569  }
8570 
8571  int EXArray[16][2] =
8572  {{4, 6}, {2, 8}, // horizontal & vertical
8573  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
8574  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
8575  {1, 9}, {3, 7}}; // forward & reverse diagonals
8576 
8577  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
8578  Graphics::TBitmap *Bitmap;
8579 
8580  if(FirstTrack)
8581  {
8582  InLink = TrackElement.Link[0];
8583  OutLink = TrackElement.Link[1];
8584  }
8585  else
8586  {
8587  InLink = TrackElement.Link[2];
8588  OutLink = TrackElement.Link[3];
8589  }
8590 
8591  for(int x = 0; x < 16; x++)
8592  {
8593  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
8594  Index = x;
8595  }
8596  if(Index == -1)
8597  {
8598  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
8599  }
8600 
8601 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
8602  the graphic for each of which is different because of the shape of the overbridge. The basic
8603  entry/exit value is computed above, and this used to select only from elements with that entry/exit
8604  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
8605  int BrEXArray[24][2] = {
8606  {4,6},{2,8},{1,9},{3,7},
8607  {1,9},{3,7},{1,9},{3,7},
8608  {2,8},{4,6},{2,8},{4,6}
8609 */
8610  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8611  {
8612  if(Index == 1)
8613  {
8614  if(TrackElement.SpeedTag == 49)
8615  BrNum = 1 + 16;
8616  else if(TrackElement.SpeedTag == 54)
8617  BrNum = 8 + 16;
8618  else if(TrackElement.SpeedTag == 55)
8619  BrNum = 10 + 16;
8620  }
8621  else if(Index == 0)
8622  {
8623  if(TrackElement.SpeedTag == 48)
8624  BrNum = 0 + 16;
8625  else if(TrackElement.SpeedTag == 58)
8626  BrNum = 11 + 16;
8627  else if(TrackElement.SpeedTag == 59)
8628  BrNum = 9 + 16;
8629  }
8630  else if(Index == 14)
8631  {
8632  if(TrackElement.SpeedTag == 50)
8633  BrNum = 2 + 16;
8634  else if(TrackElement.SpeedTag == 52)
8635  BrNum = 4 + 16;
8636  else if(TrackElement.SpeedTag == 57)
8637  BrNum = 6 + 16;
8638  }
8639  else if(Index == 15)
8640  {
8641  if(TrackElement.SpeedTag == 51)
8642  BrNum = 3 + 16;
8643  else if(TrackElement.SpeedTag == 53)
8644  BrNum = 7 + 16;
8645  else if(TrackElement.SpeedTag == 56)
8646  BrNum = 5 + 16;
8647  }
8648  }
8649 
8650  if(!FirstTrack && (TrackElement.TrackType == Bridge))
8651  GrNum = BrNum;
8652  else
8653  GrNum = Index;
8654 
8655  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
8656  {
8657  if(GrNum > 15) // underbridge
8658  {
8659  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
8660  }
8661  else
8662  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
8663 
8664  if(TrackElement.SpeedTag == 64)
8665  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8666  if(TrackElement.SpeedTag == 65)
8668  if(TrackElement.SpeedTag == 66)
8670  if(TrackElement.SpeedTag == 67)
8672 
8673  if(TrackElement.SpeedTag == 80)
8674  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
8675  if(TrackElement.SpeedTag == 81)
8677  if(TrackElement.SpeedTag == 82)
8679  if(TrackElement.SpeedTag == 83)
8681  if(TrackElement.SpeedTag == 84)
8683  if(TrackElement.SpeedTag == 85)
8685  if(TrackElement.SpeedTag == 86)
8687  if(TrackElement.SpeedTag == 87)
8689 
8690  if(TrackElement.SpeedTag == 129)
8691  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
8692  if(TrackElement.SpeedTag == 130)
8694  }
8695 
8696  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
8697  {
8698  if(GrNum > 15) // underbridge
8699  {
8700  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
8701  }
8702  else
8703  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
8704 
8705  if(TrackElement.SpeedTag == 64)
8706  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8707  if(TrackElement.SpeedTag == 65)
8708  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
8709  if(TrackElement.SpeedTag == 66)
8710  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
8711  if(TrackElement.SpeedTag == 67)
8712  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
8713 
8714  if(TrackElement.SpeedTag == 80)
8715  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8716  if(TrackElement.SpeedTag == 81)
8717  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
8718  if(TrackElement.SpeedTag == 82)
8719  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
8720  if(TrackElement.SpeedTag == 83)
8721  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
8722  if(TrackElement.SpeedTag == 84)
8723  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
8724  if(TrackElement.SpeedTag == 85)
8725  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
8726  if(TrackElement.SpeedTag == 86)
8727  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
8728  if(TrackElement.SpeedTag == 87)
8729  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
8730 
8731  if(TrackElement.SpeedTag == 129)
8732  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
8733  if(TrackElement.SpeedTag == 130)
8734  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
8735  }
8736 
8737  else // SpeedDifferent only: red - use non sig graphics
8738  {
8739  if(GrNum > 15) // underbridge
8740  {
8741  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
8742  }
8743  else
8744  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
8745 
8746  if(TrackElement.SpeedTag == 64)
8747  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
8748  if(TrackElement.SpeedTag == 65)
8750  if(TrackElement.SpeedTag == 66)
8752  if(TrackElement.SpeedTag == 67)
8754 
8755  if(TrackElement.SpeedTag == 80)
8756  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
8757  if(TrackElement.SpeedTag == 81)
8759  if(TrackElement.SpeedTag == 82)
8761  if(TrackElement.SpeedTag == 83)
8763  if(TrackElement.SpeedTag == 84)
8765  if(TrackElement.SpeedTag == 85)
8767  if(TrackElement.SpeedTag == 86)
8769  if(TrackElement.SpeedTag == 87)
8771 
8772  if(TrackElement.SpeedTag == 129)
8773  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
8774  if(TrackElement.SpeedTag == 130)
8776  }
8777 
8778  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
8779  Utilities->CallLogPop(620);
8780 }
8781 
8782 // ---------------------------------------------------------------------------
8783 
8784 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
8785 /* FirstTrack = LinkPos's 0 & 1
8786  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
8787 */
8788 {
8789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
8790  AnsiString((short)FirstTrack));
8791  LengthDifferent = false;
8792  SpeedDifferent = false;
8793  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
8794  {
8795  if(TrackElement.Length01 != DefaultTrackLength)
8796  {
8797  LengthDifferent = true;
8798  }
8799  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8800  {
8801  SpeedDifferent = true;
8802  }
8803  if(LengthDifferent || SpeedDifferent)
8804  {
8805  Utilities->CallLogPop(625);
8806  return false;
8807  }
8808  Utilities->CallLogPop(626);
8809  return true;
8810  }
8811 
8812  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
8813  {
8814  if(TrackElement.Length23 != DefaultTrackLength)
8815  {
8816  LengthDifferent = true;
8817  }
8818  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
8819  {
8820  SpeedDifferent = true;
8821  }
8822  if(LengthDifferent || SpeedDifferent)
8823  {
8824  Utilities->CallLogPop(627);
8825  return false;
8826  }
8827  Utilities->CallLogPop(628);
8828  return true;
8829  }
8830 
8831  else // any other 1 track element, including platforms being present
8832  {
8833  if(TrackElement.Length01 != DefaultTrackLength)
8834  {
8835  LengthDifferent = true;
8836  }
8837  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
8838  {
8839  SpeedDifferent = true;
8840  }
8841  if(LengthDifferent || SpeedDifferent)
8842  {
8843  Utilities->CallLogPop(629);
8844  return false;
8845  }
8846  Utilities->CallLogPop(630);
8847  return true;
8848  }
8849 }
8850 
8851 // ---------------------------------------------------------------------------
8852 
8853 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
8854  // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
8855 {
8856  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
8857  AnsiString(VLoc));
8858  bool FoundFlag;
8859  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
8860 
8861  if(!FoundFlag)
8862  {
8863  Utilities->CallLogPop(633);
8864  return false;
8865  }
8866  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
8867  {
8868  Utilities->CallLogPop(634);
8869  return true; // only need to check first since if second is a platform the the first must be too
8870  }
8871  else
8872  {
8873  Utilities->CallLogPop(635);
8874  return false;
8875  }
8876 }
8877 
8878 // ---------------------------------------------------------------------------
8879 
8880 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
8881  // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
8882 {
8883  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
8884  AnsiString(VLoc));
8885  bool FoundFlag;
8886  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
8887 
8888  if(!FoundFlag)
8889  {
8890  Utilities->CallLogPop(636);
8891  return false;
8892  }
8894  {
8895  Utilities->CallLogPop(637);
8896  return true; // only need to check first since only one used for NamedNonStationLocations
8897  }
8898  else
8899  {
8900  Utilities->CallLogPop(638);
8901  return false;
8902  }
8903 }
8904 
8905 // ---------------------------------------------------------------------------
8906 
8908 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
8909  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
8910  the front of train stop points for each direction.
8911  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
8912  end (unless buffers at one or both ends in which case stop points are the end elements).
8913  Note that for a single element the stop point is the element itself (formula doesn't apply).
8914  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
8915  repeating the procedure for every element. At the end all unused values are returned to -1.
8916  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
8917 */
8918 {
8919  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
8920  TTrackElement TempElement, StartElement;
8921  AnsiString TempName;
8922  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
8923  bool ForwardSet, ReverseSet;
8924 
8925  for(unsigned int x = 0; x < TrackVector.size(); x++)
8926  {
8927  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
8928  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
8929  }
8930  for(unsigned int x = 0; x < TrackVector.size(); x++)
8931  {
8932  ForwardSet = false;
8933  ReverseSet = false;
8934  TempElement = TrackVector.at(x);
8935  VecPos = x;
8936  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
8937  // 2nd condition incl so don't re-examine elements with stop links set to 5
8938  {
8939  TempName = TempElement.ActiveTrackElementName;
8940  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
8941  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
8942  // an element linked at both ends where both links are also named elements
8943  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
8944  {
8945  continue; // looking for an end element so skip this one
8946  }
8947  else // reached one end
8948  {
8949  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
8950  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
8951  // single named element linked at both ends
8952  {
8953  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
8954  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
8955  continue;
8956  }
8957  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
8958  // single named buffer element (LinkPos 1 is the non-buffer end)
8959  {
8960  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
8961  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
8962  continue;
8963  }
8964  else
8965  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
8966  // and platforms always on straight (conns 0 & 1) section of points
8967  {
8968  for(int y = 0; y < 2; y++)
8969  {
8970  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
8971  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
8972 /* TTrackElement Temp1 = TempElement;
8973  ***********New section, compiles but not checked - does bit below need to be else if?
8974  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
8975  {
8976  //search along Dir direction until find other end, skip if Dir facing buffer end
8977  int NewDir = Dir;
8978  int NewVecPos;
8979  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
8980  {
8981  NewVecPos = Temp1.Conn[NewDir];
8982  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
8983  Temp1 = TrackElementAt(601, NewVecPos);
8984  }
8985  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
8986  {
8987  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
8988  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
8989  }
8990  }
8991  ***************
8992 */
8993  // end may be linked at both ends but only one link named, or buffer with linked element named
8994  // if a buffer then the named linkpos has to be 1
8995  // already dealt with all types of single element so at least 2 linked named element
8996  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
8997  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
8998  {
8999  StartElement = TempElement;
9000  StartVecPos = VecPos;
9001  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
9002  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
9003  EntryPos = 1 - Dir;
9004  StartEntryPos = 1 - Dir;
9005  Count = 1;
9006  // work along named elements until find the other end
9007  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
9008  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
9009  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
9010  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
9011  // all stop link pos's are set to 5
9012  {
9013  VecPos = TempElement.Conn[1 - EntryPos];
9014  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9015  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
9016  EntryPos = TempEntryPos;
9017  Count++;
9018  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
9019  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
9020  }
9021  // here when reached other end, maybe buffers, continuation or last named linked element
9022  if(TrackElementAt(57, VecPos).TrackType == Buffers)
9023  // terminal station, set end elements as stop elements
9024  {
9025  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
9026  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
9027  continue;
9028  }
9029  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
9030  // terminal station, set end elements as stop elements
9031  {
9032  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
9033  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9034  continue;
9035  }
9036  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
9037  // NonStationLocation so set end elements as stop elements
9038  {
9039  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
9040  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9041  continue;
9042  }
9043  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
9044  ForwardNumber = ((Count + 1) / 2) + 1;
9045  ReverseNumber = (Count - ForwardNumber) + 1;
9046  Count = 1; // starting value
9047  EntryPos = 1 - Dir;
9048  TempElement = StartElement;
9049  VecPos = StartVecPos;
9050  if(Count == ForwardNumber)
9051  {
9052  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
9053  ForwardSet = true;
9054  }
9055  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
9056  {
9057  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9058  ReverseSet = true;
9059  }
9060  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
9061  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
9062  {
9063  VecPos = TempElement.Conn[1 - EntryPos];
9064  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9065  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
9066  EntryPos = TempEntryPos;
9067  Count++;
9068  if(Count == ForwardNumber)
9069  {
9070  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
9071  ForwardSet = true;
9072  }
9073  if(Count == ReverseNumber)
9074  {
9075  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9076  ReverseSet = true;
9077  }
9078  }
9079  }
9080  }
9081  }
9082  }
9083  }
9084  }
9085  for(unsigned int x = 0; x < TrackVector.size(); x++)
9086  {
9087  if(TrackVector.at(x).StationEntryStopLinkPos1 == 5)
9088  {
9089  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
9090  }
9091  if(TrackVector.at(x).StationEntryStopLinkPos2 == 5)
9092  {
9093  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
9094  }
9095  }
9096  Utilities->CallLogPop(639);
9097 }
9098 
9099 // ---------------------------------------------------------------------------
9100 
9101 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
9102 {
9103  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
9104  TTrackElement Next;
9105 
9107  while(ReturnNextInactiveTrackElement(1, Next))
9108  {
9109  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
9110  {
9111  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
9112  // need striped graphics
9113  {
9114  if(Next.SpeedTag == 76)
9115  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
9116  else if(Next.SpeedTag == 77)
9117  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
9118  else if(Next.SpeedTag == 78)
9119  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
9120  else if(Next.SpeedTag == 79)
9121  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
9122  else if(Next.SpeedTag == 96)
9123  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
9124  else if(Next.SpeedTag == 131)
9125  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
9126  }
9127  else
9128  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
9129  }
9130  }
9131 
9132  NextTrackElementPtr = TrackVector.begin();
9133  while(ReturnNextTrackElement(1, Next))
9134  {
9135  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
9136  {
9137  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
9138  {
9139  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
9140  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
9141  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
9142  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
9143  }
9144  else
9145  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
9146  }
9147  }
9148  Disp->Update();
9149  Utilities->CallLogPop(640);
9150 }
9151 
9152 // ---------------------------------------------------------------------------
9153 
9154 void TTrack::PlotSmallRedGap(int Caller)
9155 {
9156  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
9158  Utilities->CallLogPop(1346);
9159 }
9160 
9161 // ---------------------------------------------------------------------------
9162 
9163 void TTrack::TrackClear(int Caller)
9164 {
9165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
9166  TrackVector.clear();
9167  InactiveTrackVector.clear();
9168  TrackMap.clear();
9170  if(TextHandler->TextVector.size() == 0)
9171  {
9172  Display->DisplayOffsetH = 0;
9173  Display->DisplayOffsetV = 0;
9180  HLocMin = 2000000000;
9181  HLocMax = -2000000000;
9182  VLocMin = 2000000000;
9183  VLocMax = -2000000000;
9184  }
9185  else
9186  CalcHLocMinEtc(4);
9187  Utilities->CallLogPop(1347);
9188 }
9189 
9190 // ---------------------------------------------------------------------------
9191 
9192 void TTrack::CalcHLocMinEtc(int Caller)
9193 {
9194  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
9195  HLocMin = 2000000000;
9196  VLocMin = 2000000000;
9197  HLocMax = -2000000000;
9198  VLocMax = -2000000000;
9199  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
9200  {
9201  if(TrackVector.at(x).SpeedTag == 0)
9202  continue; // skip erase elements or would interfere with Min & Max values
9203  if(TrackVector.at(x).HLoc - 1 < HLocMin)
9204  HLocMin = TrackVector.at(x).HLoc - 1; // add one all round
9205  if(TrackVector.at(x).HLoc + 1 > HLocMax)
9206  HLocMax = TrackVector.at(x).HLoc + 1;
9207  if(TrackVector.at(x).VLoc - 1 < VLocMin)
9208  VLocMin = TrackVector.at(x).VLoc - 1;
9209  if(TrackVector.at(x).VLoc + 1 > VLocMax)
9210  VLocMax = TrackVector.at(x).VLoc + 1;
9211  }
9212  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
9213  {
9214  if(InactiveTrackVector.at(x).SpeedTag == 0)
9215  continue; // shouldn't be any inactive erase elements but include anyway
9216  if(InactiveTrackVector.at(x).HLoc - 1 < HLocMin)
9217  HLocMin = InactiveTrackVector.at(x).HLoc - 1; // add one all round
9218  if(InactiveTrackVector.at(x).HLoc + 1 > HLocMax)
9219  HLocMax = InactiveTrackVector.at(x).HLoc + 1;
9220  if(InactiveTrackVector.at(x).VLoc - 1 < VLocMin)
9221  VLocMin = InactiveTrackVector.at(x).VLoc - 1;
9222  if(InactiveTrackVector.at(x).VLoc + 1 > VLocMax)
9223  VLocMax = InactiveTrackVector.at(x).VLoc + 1;
9224  }
9225  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
9226  {
9227 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
9228  will fail as x will exceed the maximum value
9229  if(TextHandler->TextPtrAt(, x)->TextString == "")
9230  {
9231  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
9232  }
9233 */
9234  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
9235  if((TextH / 16) - 1 < HLocMin)
9236  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
9237  if((TextH / 16) + 1 > HLocMax)
9238  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
9239  if((TextV / 16) - 1 < VLocMin)
9240  VLocMin = (TextV / 16) - 1;
9241  if((TextV / 16) + 1 > VLocMax)
9242  VLocMax = (TextV / 16) + 1;
9243  }
9244  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
9245  {
9246  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
9247  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
9248  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
9249  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
9250  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
9251  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
9252  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
9253  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
9254  }
9255 
9256  Utilities->CallLogPop(641);
9257 }
9258 
9259 // ---------------------------------------------------------------------------
9260 
9261 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
9262  bool &UserGraphicFoundFlag)
9263 {
9264  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
9265  TUserGraphicVector::iterator UserGraphicPtr;
9266 
9267  UserGraphicFoundFlag = false;
9268  if(!UserGraphicVector.empty())
9269  {
9270  int x = UserGraphicVector.size();
9271  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
9272  {
9273  x--;
9274  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
9275  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
9276  {
9277  UserGraphicItem = x;
9278  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
9279  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
9280  UserGraphicFoundFlag = true;
9281  Utilities->CallLogPop(2177);
9282  return;
9283  } // if ....
9284  } // for UserGraphicPtr...
9285  } // if !UserGraphicVector...
9286  Utilities->CallLogPop(2197);
9287 }
9288 
9289 // ---------------------------------------------------------------------------
9290 
9292 {
9293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
9294  TrackElement.LogTrack(11));
9295  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
9296  int SpeedTag = TrackElement.SpeedTag;
9297 
9298  if(SpeedTag < 1)
9299  {
9300  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
9301  }
9302  switch(SpeedTag)
9303  {
9304  case 76: // t platform
9305  GraphicOutput = RailGraphics->gl76Striped;
9306  break;
9307 
9308  case 77: // h platform
9309  GraphicOutput = RailGraphics->bm77Striped;
9310  break;
9311 
9312  case 78: // v platform
9313  GraphicOutput = RailGraphics->bm78Striped;
9314  break;
9315 
9316  case 79: // r platform
9317  GraphicOutput = RailGraphics->gl79Striped;
9318  break;
9319 
9320  case 96: // concourse
9321  GraphicOutput = RailGraphics->ConcourseStriped;
9322  break;
9323 
9324  case 129: // v footbridge
9325  GraphicOutput = RailGraphics->gl129Striped;
9326  break;
9327 
9328  case 130: // h footbridge
9329  GraphicOutput = RailGraphics->gl130Striped;
9330  break;
9331 
9332  case 131: // non-station named loc
9333  GraphicOutput = RailGraphics->bmNameStriped;
9334  break;
9335 
9336  case 145: // v u'pass
9337  GraphicOutput = RailGraphics->gl145Striped;
9338  break;
9339 
9340  case 146: // h u'pass
9341  GraphicOutput = RailGraphics->gl146Striped;
9342  break;
9343 
9344  default:
9345  GraphicOutput = TrackElement.GraphicPtr;
9346  break;
9347  }
9348  Utilities->CallLogPop(642);
9349  return GraphicOutput;
9350 }
9351 
9352 // ---------------------------------------------------------------------------
9353 
9355 {
9356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
9357  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
9358  {
9359  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
9360  }
9361  Utilities->CallLogPop(643);
9362  return TrackVector.at(At);
9363 }
9364 
9365 // ---------------------------------------------------------------------------
9366 
9368 {
9369  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
9370  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
9371  {
9372  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
9373  " in InactiveTrackElementAt");
9374  }
9375  Utilities->CallLogPop(644);
9376  return InactiveTrackVector.at(At);
9377 }
9378 
9379 // ---------------------------------------------------------------------------
9380 
9381 bool TTrack::BlankElementAt(int Caller, int At) const
9382 {
9383  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
9384  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
9385  {
9386  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
9387  }
9388  if(TrackVector.at(At).SpeedTag == 0)
9389  {
9390  Utilities->CallLogPop(645);
9391  return true;
9392  }
9393  else
9394  {
9395  Utilities->CallLogPop(646);
9396  return false;
9397  }
9398 }
9399 
9400 // ---------------------------------------------------------------------------
9401 
9402 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
9403 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
9404  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
9405  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
9406  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
9407  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
9408 */
9409 {
9410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
9411  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
9412  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
9413  TLocationNameMultiMapIterator SNIterator;
9414  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9415 
9416  if(SNRange.first == SNRange.second)
9417  {
9418  Utilities->CallLogPop(972);
9419  return false; // should have been caught earlier but include for completeness
9420  }
9421  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9422  {
9423  if(SNIterator->second < 0)
9424  continue; // exclude footcrossings
9425  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
9426  if(InactiveElement.TrackType == Concourse)
9427  continue; // only interested in locations where ActiveTrackElementName may be set
9428  THVPair HVPair;
9429  HVPair.first = InactiveElement.HLoc;
9430  HVPair.second = InactiveElement.VLoc;
9431  if(TrackMap.find(HVPair) == TrackMap.end())
9432  {
9433  throw Exception
9434  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
9435  }
9436  int TVPos = TrackMap.find(HVPair)->second;
9437  FirstNamedElement = TrackElementAt(560, TVPos);
9438  // first check linked on both sides, skip the check if not
9439  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9440  {
9441  continue;
9442  }
9443  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9444  // ActiveTrackElementNames are points and excluding trailing connections for points
9445  FirstNamedExitPos = 0;
9446  {
9447  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
9448  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9449  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9450  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9451  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9452  {
9453  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9454  {
9455  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
9456  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9457  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9458  // success, now check FirstNamedElement link not trailing points & if so all OK
9459  {
9460  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9461  {
9462  Utilities->CallLogPop(1002);
9463  return true;
9464  }
9465  }
9466  }
9467  }
9468  }
9469  // failed, try link 1
9470  FirstNamedExitPos = 1;
9471  {
9472  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
9473  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9474  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9475  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9476  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9477  {
9478  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9479  {
9480  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
9481  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9482  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9483  // success, now check FirstNamedElement link not trailing points & if so all OK
9484  {
9485  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9486  {
9487  Utilities->CallLogPop(1003);
9488  return true;
9489  }
9490  }
9491  }
9492  }
9493  }}
9494  Utilities->CallLogPop(1004);
9495  return false;
9496 }
9497 
9498 // ---------------------------------------------------------------------------
9499 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
9500  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
9501  // for success need two linked named location elements, so that one element of each train can be at the location
9502  // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
9503  // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
9504  // the two trains will occupy these 4 elements
9505  // All are track vector positions, all but the input being references and set within the function.
9506 {
9507 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
9508  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
9509  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
9510  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
9511  splitting.
9512 */
9513  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
9514  AnsiString(FirstNamedElementPos));
9515  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
9516  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
9517 
9518  SecondNamedElementPos = -1;
9519  FirstNamedLinkedElementPos = -1;
9520  SecondNamedLinkedElementPos = -1;
9521  TLocationNameMultiMapIterator SNIterator;
9522  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9523 
9524  if(SNRange.first == SNRange.second) // i.e. location name not in map
9525  {
9526  Utilities->CallLogPop(1005);
9527  return false; // should have been caught earlier but include for completeness
9528  }
9529  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9530  {
9531  if(SNIterator->second < 0)
9532  continue; // exclude footcrossings
9533  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
9534  if(InactiveElement.TrackType == Concourse)
9535  continue; // only interested in locations where ActiveTrackElementName may be set
9536  THVPair HVPair;
9537  HVPair.first = InactiveElement.HLoc;
9538  HVPair.second = InactiveElement.VLoc;
9539  if(TrackMap.find(HVPair) == TrackMap.end())
9540  {
9541  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
9542  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
9543  // then it won't be found in TrackMap but it's still legitimate.
9544  {
9545  continue;
9546  }
9547  else // for anything else throw the error
9548  {
9549  throw Exception
9550  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
9551  );
9552  }
9553  }
9554  int TVPos = TrackMap.find(HVPair)->second;
9555  if(TVPos != FirstNamedElementPos)
9556  continue; // looking for an exact match
9557  FirstNamedElement = TrackElementAt(567, TVPos);
9558  // first check linked on both sides, skip the check if not
9559  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
9560  {
9561  continue;
9562  }
9563  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
9564  // ActiveTrackElementNames are points and excluding trailing connections for points
9565  FirstNamedExitPos = 0;
9566  {
9567  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
9568  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9569  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9570  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9571  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9572  {
9573  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9574  {
9575  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
9576  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9577  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9578  // success, now check FirstNamedElement link not trailing points & if so all OK
9579  {
9580  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9581  {
9582  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9583  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9584  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9585  Utilities->CallLogPop(1006);
9586  return true;
9587  }
9588  }
9589  }
9590  }
9591  }
9592  // failed, try link 1
9593  FirstNamedExitPos = 1;
9594  {
9595  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
9596  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
9597  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
9598  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
9599  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
9600  {
9601  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
9602  {
9603  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
9604  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
9605  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
9606  // success, now check FirstNamedElement link not trailing points & if so all OK
9607  {
9608  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
9609  {
9610  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
9611  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
9612  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
9613  Utilities->CallLogPop(1007);
9614  return true;
9615  }
9616  }
9617  }
9618  }
9619  }}
9620  Utilities->CallLogPop(1008);
9621  return false;
9622 }
9623 
9624 // ---------------------------------------------------------------------------
9625 
9626 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
9627 {
9628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
9629  TLocationNameMultiMapIterator SNIterator;
9630  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9631 
9632  if(SNRange.first != SNRange.second)
9633  {
9634  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9635  {
9636  if(SNIterator->second < 0)
9637  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
9638  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
9639  SNIterator->second).TrackType == NamedNonStationLocation))
9640  {
9641  Utilities->CallLogPop(1121);
9642  return true;
9643  }
9644  }
9645  }
9646  Utilities->CallLogPop(848);
9647  return false;
9648 }
9649 
9650 // ---------------------------------------------------------------------------
9651 
9652 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
9653 {
9654 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
9655  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
9656  "," + AnsiString(SpeedTag));
9657  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
9658  {
9659  Utilities->CallLogPop(949);
9660  return false;
9661  }
9662  bool FoundFlag;
9663  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
9664 
9665  if(!FoundFlag)
9666  {
9667  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
9668  }
9669  TTrackElement IAElement;
9670 
9671  if(SpeedTag == 68) // top sig
9672  {
9673  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
9674  {
9675  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
9676  IAElement = InactiveTrackElementAt(50, IMPair.first);
9677  else
9678  IAElement = InactiveTrackElementAt(51, IMPair.second);
9679  if(IAElement.LocationName == "")
9680  {
9681 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
9682  SignalPlatformGraphic = RailGraphics->gl76Striped;
9683  }
9684  else
9685  {
9686 // SignalPlatformGraphic = RailGraphics->Plat68;
9687  SignalPlatformGraphic = RailGraphics->gl76;
9688  }
9689  Utilities->CallLogPop(950);
9690  return true;
9691  }
9692  }
9693  else if(SpeedTag == 69) // bot sig
9694  {
9695  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
9696  {
9697  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
9698  IAElement = InactiveTrackElementAt(77, IMPair.first);
9699  else
9700  IAElement = InactiveTrackElementAt(78, IMPair.second);
9701  if(IAElement.LocationName == "")
9702  {
9703 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
9704  SignalPlatformGraphic = RailGraphics->bm77Striped;
9705  }
9706  else
9707  {
9708 // SignalPlatformGraphic = RailGraphics->Plat69;
9709  SignalPlatformGraphic = RailGraphics->bm77;
9710  }
9711  Utilities->CallLogPop(951);
9712  return true;
9713  }
9714  }
9715  else if(SpeedTag == 70) // left sig
9716  {
9717  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
9718  {
9719  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
9720  IAElement = InactiveTrackElementAt(55, IMPair.first);
9721  else
9722  IAElement = InactiveTrackElementAt(82, IMPair.second);
9723  if(IAElement.LocationName == "")
9724  {
9725 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
9726  SignalPlatformGraphic = RailGraphics->bm78Striped;
9727  }
9728  else
9729  {
9730 // SignalPlatformGraphic = RailGraphics->Plat70;
9731  SignalPlatformGraphic = RailGraphics->bm78;
9732  }
9733  Utilities->CallLogPop(952);
9734  return true;
9735  }
9736  }
9737  else if(SpeedTag == 71) // right sig
9738  {
9739  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
9740  {
9741  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
9742  IAElement = InactiveTrackElementAt(85, IMPair.first);
9743  else
9744  IAElement = InactiveTrackElementAt(86, IMPair.second);
9745  if(IAElement.LocationName == "")
9746  {
9747 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
9748  SignalPlatformGraphic = RailGraphics->gl79Striped;
9749  }
9750  else
9751  {
9752 // SignalPlatformGraphic = RailGraphics->Plat71;
9753  SignalPlatformGraphic = RailGraphics->gl79;
9754  }
9755  Utilities->CallLogPop(953);
9756  return true;
9757  }
9758  }
9759  Utilities->CallLogPop(954);
9760  return false;
9761 }
9762 
9763 // ---------------------------------------------------------------------------
9764 
9765 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
9766  // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
9767  // false if not, if NextPos == -1, or if only own train on the track
9768 {
9769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
9770  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
9771  if(NextEntryPos < 0)
9772  {
9773  Utilities->CallLogPop(1348);
9774  return false;
9775  }
9776  TTrackElement TrackElement = TrackElementAt(713, NextPos);
9777 
9778  if(TrackElement.TrackType != Bridge)
9779  {
9780  Utilities->CallLogPop(1349);
9781  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
9782  }
9783 // bridge if reach here
9784  if(NextEntryPos > 1)
9785  {
9786  Utilities->CallLogPop(1350);
9787  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
9788  }
9789  else
9790  {
9791  Utilities->CallLogPop(1351);
9792  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
9793  }
9794 }
9795 
9796 // ---------------------------------------------------------------------------
9797 
9799 {
9800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
9801  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
9802  {
9803  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
9804  }
9805  Utilities->CallLogPop(1483);
9806  return SelectVector.at(At);
9807 }
9808 
9809 // ---------------------------------------------------------------------------
9810 
9811 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
9812  // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
9813 {
9814  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
9815  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
9816  bool FoundFlag = false;
9817  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
9818  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
9819 
9820  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
9821  Utilities->CallLogPop(1538);
9822  return FoundFlag;
9823 }
9824 
9825 // ---------------------------------------------------------------------------
9826 
9827 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
9828 {
9829 // return true if find an inactive element called 'Name'
9830  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
9831  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
9832  bool FoundFlag = false;
9833 
9834  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9835  {
9836  if(InactiveTrackVector.at(x).LocationName == Name)
9837  {
9838  FoundFlag = true;
9839  int V = InactiveTrackVector.at(x).VLoc;
9840  int H = InactiveTrackVector.at(x).HLoc;
9841  if(V > VLocHi)
9842  VLocHi = V;
9843  if(V < VLocLo)
9844  VLocLo = V;
9845  if(H < HLoc)
9846  HLoc = H;
9847  }
9848  }
9849  if(FoundFlag)
9850  {
9851  VPosHi = 16 * VLocHi;
9852  VPosLo = 16 * VLocLo;
9853  HPos = 16 * HLoc;
9854  Utilities->CallLogPop(1562);
9855  return true;
9856  }
9857  else
9858  {
9859  Utilities->CallLogPop(1563);
9860  return false;
9861  }
9862 }
9863 
9864 // ---------------------------------------------------------------------------
9865 
9866 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
9867 {
9868 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
9869 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
9870  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
9871  AnsiString(EndTVPosition));
9872  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
9873  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
9874 
9875 // get H & V values for the element adjacent to Link[0] & Link[1]
9876  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
9877  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
9878  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
9879  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
9880 
9881 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
9882  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
9883  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
9884  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
9885  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
9886 
9887  if(Link0Squares <= Link1Squares)
9888  {
9889  Utilities->CallLogPop(1851);
9890  return 0;
9891  }
9892  else
9893  {
9894  Utilities->CallLogPop(1852);
9895  return 1;
9896  }
9897 }
9898 
9899 // ---------------------------------------------------------------------------
9900 
9901 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
9902 { // element can be points or any other type
9903  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
9904  AnsiString(LinkPos));
9905  Derail = false;
9906  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
9907 
9908  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
9909  {
9910  if(TE.Attribute == 0)
9911  {
9912  Utilities->CallLogPop(663);
9913  return 1; // Att == 0 & ExitPos == 1 represent straight
9914  }
9915  else
9916  {
9917  Utilities->CallLogPop(664);
9918  return 3; // Att == 1 & ExitPos == 3 represent diverging
9919  }
9920  }
9921  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
9922  {
9923  if((LinkPos == 1) && (TE.Attribute == 0))
9924  {
9925  Utilities->CallLogPop(665);
9926  return 0; // Att == 0 represents straight
9927  }
9928  else if(LinkPos == 1)
9929  {
9930  Derail = true;
9931  Utilities->CallLogPop(666);
9932  return 0;
9933  }
9934  else if((LinkPos == 3) && (TE.Attribute == 1))
9935  {
9936  Utilities->CallLogPop(667);
9937  return 0;
9938  }
9939  else if(LinkPos == 3)
9940  {
9941  Derail = true;
9942  Utilities->CallLogPop(668);
9943  return 0;
9944  }
9945  }
9946  else if(LinkPos == 0)
9947  {
9948  Utilities->CallLogPop(669);
9949  return 1;
9950  }
9951  else if(LinkPos == 1)
9952  {
9953  Utilities->CallLogPop(670);
9954  return 0;
9955  }
9956  else if(LinkPos == 2)
9957  {
9958  Utilities->CallLogPop(671);
9959  return 3;
9960  }
9961  else if(LinkPos == 3)
9962  {
9963  Utilities->CallLogPop(672);
9964  return 2;
9965  }
9966  throw Exception("Error, failure in GetExitPos"); // should never reach here
9967 }
9968 
9969 // ----------------------------------------------------------------------------
9970 
9972 {
9973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
9974  LCVector.clear();
9975  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9976  {
9977  if(InactiveTrackVector.at(x).TrackType == LevelCrossing)
9978  {
9979  LCVector.push_back(x);
9980  }
9981  }
9982  Utilities->CallLogPop(1931);
9983  return;
9984 }
9985 
9986 // ---------------------------------------------------------------------------
9987 
9988 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
9989 /*
9990  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
9991  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
9992  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
9993  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
9994 */
9995 {
9996  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9997  AnsiString(Link));
9998  bool FoundFlag;
9999 
10000  TrainID = -1;
10001  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
10002 
10003  if(!FoundFlag)
10004  {
10005  Utilities->CallLogPop(2001);
10006  return false;
10007  }
10008  TTrackElement TE = TrackElementAt(882, VecPos);
10009 
10010  TrainID = TE.TrainIDOnElement;
10011  if(TE.TrackType == Bridge)
10012  {
10013  if(TE.TrainIDOnElement > -1)
10014  {
10015  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
10016  {
10017  TrainID = TE.TrainIDOnBridgeTrackPos01;
10018  }
10019  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
10020  {
10021  TrainID = TE.TrainIDOnBridgeTrackPos23;
10022  }
10023  else
10024  TrainID = -1; // shouldn't ever reach here but be safe
10025  }
10026  }
10027  if(TrainID == -1)
10028  {
10029  Utilities->CallLogPop(2002);
10030  return false;
10031  }
10032 // now get the train
10033  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
10034 
10035  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
10036  {
10037  Utilities->CallLogPop(2003);
10038  return true;
10039  }
10040  TrainID = -1;
10041  Utilities->CallLogPop(2004);
10042  return false;
10043 }
10044 
10045 // ---------------------------------------------------------------------------
10046 
10047 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
10048 /* New at v1.2.0
10049  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
10050  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
10051  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
10052  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
10053  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
10054  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
10055  Each of these is examined in turn for each route element in the relevant position.
10056 */
10057 {
10058  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10059  "," + AnsiString(DiagonalLinkNumber));
10060  TrainID = -1;
10061  TPrefDirElement TempPrefDirElement;
10062  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
10063 
10064  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
10065  {
10066  Utilities->CallLogPop(2027);
10067  return true;
10068  }
10069 
10070  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
10071  {
10072  Utilities->CallLogPop(2028);
10073  return true;
10074  }
10075 
10076  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
10077  {
10078  Utilities->CallLogPop(2029);
10079  return true;
10080  }
10081 
10082  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
10083  {
10084  Utilities->CallLogPop(2030);
10085  return true;
10086  }
10087 
10088  Utilities->CallLogPop(2031);
10089  return false;
10090 }
10091 
10092 // ---------------------------------------------------------------------------
10093 
10094 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
10095 {
10096  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
10097  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
10098  TUserGraphicItem UGI;
10099  AnsiString JustFileName = "";
10100 
10101  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
10102  {
10103  UGI = UserGraphicVectorAt(17, x);
10104  int LastDelim = UGI.FileName.LastDelimiter('\\');
10105  if(LastDelim == 0) // can't find it so skip this item
10106  {
10107  continue;
10108  }
10109  else
10110  {
10111  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
10112  }
10113  Utilities->SaveFileString(VecFile, JustFileName);
10114  Utilities->SaveFileInt(VecFile, UGI.HPos);
10115  Utilities->SaveFileInt(VecFile, UGI.VPos);
10116  }
10117  Utilities->CallLogPop(2178);
10118 }
10119 
10120 // ---------------------------------------------------------------------------
10121 
10122 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
10123 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
10124 {
10125  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
10126  int NumPlats = 0;
10127  TTrackElement TempElement;
10128  int TempInt;
10129 
10130  typedef std::list<int> TNamePosList;
10131  TNamePosList NamePosList;
10132  typedef TNamePosList::iterator TNPLIt;
10133  TNPLIt NPLIt;
10134  typedef std::list<int> TOnePlatList;
10135  TOnePlatList OnePlatList;
10136  typedef TOnePlatList::iterator TOPLIt;
10137  TOPLIt OPLIt;
10138 
10139  NamePosList.clear();
10140  OnePlatList.clear();
10141  for(unsigned int x = 0; x < TrackVector.size(); x++)
10142  {
10143  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
10144  {
10145  NamePosList.push_back(x);
10146  }
10147  }
10148  //NamePosList complete
10149 
10150  if(!NamePosList.empty()) //first value for the loop examination
10151  {
10152  OnePlatList.push_back(NamePosList.back());
10153  NamePosList.pop_back(); //erase from NPV as done with it here
10154  }
10155 
10156  while(!OnePlatList.empty()) //loop to examine all linked elements
10157  {
10158  TempInt = OnePlatList.front();
10159  TempElement = TrackElementAt(989, TempInt);
10160 
10161  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
10162  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
10163  {
10164  OnePlatList.push_back(TempElement.Conn[0]);
10165  NamePosList.erase(NPLIt);
10166  }
10167  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
10168  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
10169  {
10170  OnePlatList.push_back(TempElement.Conn[1]);
10171  NamePosList.erase(NPLIt);
10172  }
10173  //here when loaded any connecting links into OnePlatList, so can erase the front element
10174  OnePlatList.erase(OnePlatList.begin());
10175  if(OnePlatList.empty())
10176  {
10177  NumPlats++; //finished with current linked elements so can increment NumPlats
10178  if(!NamePosList.empty())
10179  {
10180  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
10181  NamePosList.pop_back(); //erase from NPV as done with it there
10182  }
10183  }
10184  }
10185  Utilities->CallLogPop(2218);
10186  return NumPlats;
10187 }
10188 
10189 // ---------------------------------------------------------------------------
10190 // UserGraphic, PrefDir & Route functions
10191 // ---------------------------------------------------------------------------
10192 
10194 {
10195  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
10196  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
10197  {
10198  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
10199  }
10200  Utilities->CallLogPop(2194);
10201  return UserGraphicVector.at(At);
10202 }
10203 
10204 // ---------------------------------------------------------------------------
10205 
10206 int TOnePrefDir::LastElementNumber(int Caller) const
10207 {
10208  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
10209  int RetVal = PrefDirVector.size() - 1;
10210 
10211  if(RetVal < 0)
10212  {
10213  throw Exception("Return value negative in call to LastElementNumber");
10214  }
10215  Utilities->CallLogPop(114);
10216  return RetVal;
10217 }
10218 
10219 // ---------------------------------------------------------------------------
10221 {
10222  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
10223  if(PrefDirVector.empty())
10224  {
10225  throw Exception("PrefDirVector empty in call to LastElementPtr");
10226  }
10227  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
10228 
10229  Utilities->CallLogPop(115);
10230  return RetIT;
10231 }
10232 
10233 // ---------------------------------------------------------------------------
10235 {
10236  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
10237  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
10238  {
10239  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
10240  }
10241  Utilities->CallLogPop(116);
10242  return PrefDirVector.at(At);
10243 }
10244 
10245 // ---------------------------------------------------------------------------
10247 {
10248  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
10249  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
10250  {
10251  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
10252  " in GetModifiablePrefDirElementAt");
10253  }
10254  Utilities->CallLogPop(117);
10255  return PrefDirVector.at(At);
10256 }
10257 
10258 // ---------------------------------------------------------------------------
10260 {
10261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
10262  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
10263  {
10264  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
10265  }
10266  Utilities->CallLogPop(118);
10267  return SearchVector.at(At);
10268 }
10269 
10270 // ---------------------------------------------------------------------------
10272 {
10273  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
10274  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
10275  {
10276  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
10277  }
10278  Utilities->CallLogPop(119);
10279  return SearchVector.at(At);
10280 }
10281 
10282 // ---------------------------------------------------------------------------
10283 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
10284 /*
10285  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
10286  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
10287  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
10288  set in later functions.
10289 */
10290 {
10291  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
10292  ClearPrefDir();
10293  int TrackVectorPosition;
10294  TTrackElement TrackElement;
10295 
10296  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
10297  {
10298  Utilities->CallLogPop(126);
10299  return false;
10300  }
10301 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
10302  if(TrackElement.TrackType == Points)
10303  {
10304  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
10305  //it isn't known which trailing edge is the required PrefDir - could use the straight as
10306  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
10307  //best to prevent it to avoid problems
10308  Utilities->CallLogPop(127);
10309  return false;
10310  }
10311 */
10312  TPrefDirElement PrefDirElement(TrackElement);
10313 
10314  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
10315  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
10316  StorePrefDirElement(1, PrefDirElement); // enter first element
10317 // Note that ELink not set even if a buffer or continuation - these set in
10318 // ConvertPrefDirSearchVector after 2nd element added
10319 
10320  Utilities->CallLogPop(128);
10321  return true;
10322 }
10323 
10324 // ---------------------------------------------------------------------------
10325 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
10326 
10327 /*
10328  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
10329  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
10330  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
10331  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
10332  so that the calling function knows that the PrefDir is complete.
10333  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
10334  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
10335  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
10336  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
10337  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
10338  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
10339  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
10340  find the required element return false. CheckCount is used to keep track of set values to allow check later.
10341 */
10342 
10343 {
10344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
10345  FinishElement = false;
10346  int TrackVectorPosition;
10347 
10348  TotalSearchCount = 0;
10349  TTrackElement TrackElement, TempTrackElement;
10350 
10351  if(PrefDirVector.size() == 0)
10352  {
10353  Utilities->CallLogPop(129);
10354  return false;
10355  }
10356  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
10357  {
10358  Utilities->CallLogPop(130);
10359  return false;
10360  }
10361 
10362 // set the search limits using the last stored element in PrefDirVector as the start point
10363 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
10364 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
10365 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
10366 
10367  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
10368 
10369  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
10370  {
10371  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
10372  SearchLimitHighH = TrackElement.HLoc + 15;
10373  }
10374  else
10375  {
10376  SearchLimitLowH = TrackElement.HLoc - 15;
10377  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
10378  }
10379 
10380  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
10381  {
10382  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
10383  SearchLimitHighV = TrackElement.VLoc + 15;
10384  }
10385  else
10386  {
10387  SearchLimitLowV = TrackElement.VLoc - 15;
10388  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
10389  }
10390 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
10391  check & TotalSearchCounts check
10392  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
10393  {
10394  ShowMessage("Unable to reach the selected element - too far ahead");
10395  Utilities->CallLogPop(1692);
10396  return false;
10397  }
10398 */
10399 // get last PrefDir element
10400  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
10401  {
10402  // check if TrackElement adjacent to any of the 4 XLinkPos'
10403  for(int x = 0; x < 4; x++)
10404  {
10405  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
10406  {
10407  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
10408  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
10409  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
10410  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
10411  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
10412  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
10413  // shouldn't ever get it in a serious railway though.
10414 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
10415  }
10416  }
10417  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
10418  {
10419  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
10420  SearchVector.clear(); // use this & convert to set all PrefDir element values
10421  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
10422  {
10424  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10425  {
10426  FinishElement = true;
10427  }
10428  Utilities->CallLogPop(131);
10429  return true;
10430  }
10431  } // not an adjacent element
10432 
10433  // now check each of the 4 possible XLinkPos values
10434  for(int x = 0; x < 4; x++)
10435  {
10436  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
10437  {
10438  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
10439  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
10440  SearchVector.clear();
10441  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
10442  {
10444  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10445  {
10446  FinishElement = true;
10447  }
10448  Utilities->CallLogPop(132);
10449  return true;
10450  }
10451  }
10452  } // here if checked all possible exits without success
10453  ShowMessage(
10454  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10455  Utilities->CallLogPop(133);
10456  return false;
10457  }
10458 // dealt above with LastPrefDirElement being the start element (which can be points)
10459 
10460  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
10461  .ELinkPos] == Lead)) // leading point
10462  {
10463  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
10464  {
10465  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
10466  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
10467  // can't be buffers or gap if points
10468  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
10469  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
10470  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
10471  SearchVector.clear();
10472  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
10473  {
10475  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10476  {
10477  FinishElement = true;
10478  }
10479  Utilities->CallLogPop(134);
10480  return true;
10481  }
10482  }
10483  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
10484  {
10485  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
10486  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
10487  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
10488  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
10489  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
10490  SearchVector.clear();
10491  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
10492  {
10494  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10495  {
10496  FinishElement = true;
10497  }
10498  Utilities->CallLogPop(135);
10499  return true;
10500  }
10501  }
10502 // above dealt with immediate finds for leading point,
10503 // now deal with ordinary searches for leading point
10504  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
10505  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
10506  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
10507  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
10508  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
10509  SearchVector.clear();
10510  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
10511  {
10513  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10514  {
10515  FinishElement = true;
10516  }
10517  Utilities->CallLogPop(136);
10518  return true;
10519  }
10520  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
10521  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
10522  // note that CheckCount already increased to allow for XLinkPos & XLink
10523  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
10524  SearchVector.clear();
10525  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
10526  {
10528  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10529  {
10530  FinishElement = true;
10531  }
10532  Utilities->CallLogPop(137);
10533  return true;
10534  }
10535 // here if failed to find match for leading point
10536  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
10537  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
10538  ShowMessage(
10539  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10540  Utilities->CallLogPop(138);
10541  return false;
10542  }
10543 // leading point fully dealt with above
10544 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
10545 // separately as covered in ordinary search.
10546 
10547  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
10548  SearchVector.clear();
10549 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
10550  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
10551  {
10553  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
10554  {
10555  FinishElement = true;
10556  }
10557  Utilities->CallLogPop(139);
10558  return true;
10559  }
10560  ShowMessage(
10561  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
10562  Utilities->CallLogPop(140);
10563  return false; // failed to find required element
10564 }
10565 
10566 // ---------------------------------------------------------------------------
10567 
10568 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
10569 /*
10570  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
10571  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
10572  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
10573  Keep a count of entries in SearchVector during the current function call, so that this number can be
10574  erased for an unproductive branch search.
10575  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
10576  element. If so save it & return true. If not check if buffer, continuation, or earlier position
10577  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
10578  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
10579  If not any of above, store element in searchvector, set the new current element values from the
10580  SearchElement, then go back to the while loop for the next step in the search.
10581 */
10582 {
10583  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
10584  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
10585  int VectorCount = 0;
10586 
10587  while(true)
10588  {
10589  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
10590  {
10591  for(int x = 0; x < VectorCount; x++)
10592  SearchVector.erase(SearchVector.end() - 1);
10593  Utilities->CallLogPop(141);
10594  return false;
10595  }
10596  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
10597  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
10598  TPrefDirElement SearchElement(NextTrackElement);
10599  SearchElement.TrackVectorPosition = NextPosition;
10600  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
10601  SearchElement.ELinkPos = NextELinkPos;
10602  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
10603  int NextXLinkPos;
10604  if(SearchElement.ELinkPos == 0)
10605  NextXLinkPos = 1;
10606  if(SearchElement.ELinkPos == 1)
10607  NextXLinkPos = 0;
10608  if(SearchElement.ELinkPos == 2)
10609  NextXLinkPos = 3;
10610  if(SearchElement.ELinkPos == 3)
10611  NextXLinkPos = 2;
10612  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
10613  {
10614  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
10615  // but may be buffers, continuation or gap
10616  SearchElement.XLinkPos = NextXLinkPos;
10617  }
10618 // can't set XLink or XLinkPos yet if the element is a leading point.
10619 // check if found it
10620  if(SearchElement.TrackVectorPosition == RequiredPosition)
10621  {
10622  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
10623  VectorCount++; // not really needed but include for tidyness
10624  TotalSearchCount++;
10625  Utilities->CallLogPop(142);
10626  return true;
10627  }
10628 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
10629 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
10630 // at a time - drop this
10631 /*
10632  if(PrefDirVector.size() > 200)
10633  {
10634  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
10635  Utilities->CallLogPop(1419);
10636  return false;
10637  }
10638 */
10639 // check if a buffer or continuation
10640  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
10641  {
10642  for(int x = 0; x < VectorCount; x++)
10643  SearchVector.erase(SearchVector.end() - 1);
10644  Utilities->CallLogPop(143);
10645  return false;
10646  }
10647 // check if reached an earlier position on search PrefDir with same entry value
10648  for(unsigned int x = 0; x < SearchVector.size(); x++)
10649  {
10650  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
10651  {
10652  for(int x = 0; x < VectorCount; x++)
10653  SearchVector.erase(SearchVector.end() - 1);
10654  Utilities->CallLogPop(144);
10655  return false;
10656  }
10657  }
10658 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
10659 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
10660  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
10661  {
10662  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
10663  {
10664  for(int x = 0; x < VectorCount; x++)
10665  SearchVector.erase(SearchVector.end() - 1);
10666  Utilities->CallLogPop(1417);
10667  return false;
10668  }
10669  }
10670 
10671 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
10672 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
10673 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
10675  {
10676  for(int x = 0; x < VectorCount; x++)
10677  SearchVector.erase(SearchVector.end() - 1);
10678  Utilities->CallLogPop(1691);
10679  return false;
10680  }
10681 
10682 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
10683  if(SearchVector.size() > 150)
10684  {
10685  for(int x = 0; x < VectorCount; x++)
10686  SearchVector.erase(SearchVector.end() - 1);
10687  Utilities->CallLogPop(1418);
10688  return false;
10689  }
10690 // check if reached a leading point
10691  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
10692  {
10693 // push element with XLink set to position [1]
10694  SearchElement.XLink = SearchElement.Link[1];
10695  SearchElement.XLinkPos = 1;
10696  SearchVector.push_back(SearchElement);
10697  VectorCount++;
10698  TotalSearchCount++;
10699  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
10700  // Note that have to use a TTrackElement in the recursive search, so SearchElement
10701  // can't be used. NextTrackElement is the corresponding TTrackElement.
10702  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
10703  {
10704  Utilities->CallLogPop(145);
10705  return true;
10706  }
10707  else
10708  {
10709 // remove leading point with XLinkPos [1]
10710  SearchVector.erase(SearchVector.end() - 1);
10711  VectorCount--;
10712 // push element with XLink set to position [3]
10713  SearchElement.XLink = SearchElement.Link[3];
10714  SearchElement.XLinkPos = 3;
10715  SearchVector.push_back(SearchElement);
10716  VectorCount++;
10717  TotalSearchCount++;
10718 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
10719  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
10720  {
10721  Utilities->CallLogPop(146);
10722  return true;
10723  }
10724  else
10725  {
10726  for(int x = 0; x < VectorCount; x++)
10727  SearchVector.erase(SearchVector.end() - 1);
10728  Utilities->CallLogPop(147);
10729  return false;
10730  }
10731  }
10732  } // if leading point
10733 // here if ordinary element, push it, inc vector & update CurrentTrackElement
10734 // ready for next element on PrefDir
10735  SearchVector.push_back(SearchElement);
10736  VectorCount++;
10737  TotalSearchCount++;
10738  XLinkPos = NextXLinkPos;
10739  CurrentTrackElement = SearchElement;
10740  } // while(true)
10741 }
10742 
10743 // ---------------------------------------------------------------------------
10744 
10746 /*
10747  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
10748  for each element on the search PrefDir, though if the last element is a leading point
10749  then the final XLink won't be set.
10750  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
10751  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
10752  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
10753 */
10754 {
10755  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
10756  if(SearchVector.size() == 0)
10757  {
10758  throw Exception("Error, SearchVector empty");
10759  }
10760 // get first SearchElement in order to set last PrefDirelement
10761  TPrefDirElement SearchElement = SearchVector.at(0);
10762 
10763 // set last PrefDir element XLink & ELink values if not already set
10764 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
10765  for(int x = 0; x < 4; x++)
10766  {
10767  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
10768  {
10769  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
10770  {
10771  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
10772  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
10773  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
10774  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
10775  }
10776  int ELinkPos;
10777  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
10778  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
10779  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
10780  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
10781  ELinkPos = 0;
10782  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
10783  ELinkPos = 3;
10784  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
10785  ELinkPos = 2;
10786  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
10787  {
10788  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
10789  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
10790  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
10791  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
10792  }
10793  break; // no point going any further
10794  }
10795  }
10796 // set EXNumber for last PrefDir element, unless already set
10797 // won't be set if was first element or a leading point
10798  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
10799  {
10800 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
10801  int EXArray[32][2] = {
10802  {4,6},{2,8}, //horizontal & vertical
10803  {2,4},{6,2},{8,6},{4,8}, //sharp curves
10804  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
10805  {1,9},{3,7} //forward & reverse diagonals
10806 */
10807 
10808  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
10809  {
10810  throw Exception("Error in EntryExitNumber 1");
10811  }
10812 
10813  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
10814  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
10815  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
10816  }
10817 // Last PrefDir element now complete
10818 
10819 // construct remaining PrefDir elements from searchvector
10820  for(unsigned int x = 0; x < SearchVector.size(); x++)
10821  {
10822  SearchElement = SearchVector.at(x);
10823  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
10824  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
10825  PrefDirElement.ELink = SearchElement.ELink;
10826  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
10827  PrefDirElement.XLink = SearchElement.XLink;
10828  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
10829 // if XLink & XLinkPos not set don't account for them in CheckCount
10830  if(PrefDirElement.XLink == -1)
10831  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10832  // & TrackVectorPosition
10833  else
10834  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
10835  // XLink, XLinkPos, TrackVectorPosition
10836 
10837 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
10838  if(PrefDirElement.XLink != -1)
10839  {
10840  if(!(PrefDirElement.EntryExitNumber()))
10841  {
10842  throw Exception("Error in EntryExitNumber 2");
10843  }
10844  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
10845  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
10846  PrefDirElement.CheckCount++;
10847  // all values now incorporated if not a leading point
10848  }
10849 // store PrefDir element
10850  StorePrefDirElement(2, PrefDirElement);
10851  }
10852 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
10853  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
10854  {
10855  if(ValidatePrefDir(2))
10856  {;
10857  } // error messages given within function
10858  }
10860 /* drop this, check dropped from search
10861  if(PrefDirVector.size() > 200)
10862  {
10863  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
10864  }
10865 */
10866  Utilities->CallLogPop(148);
10867 }
10868 
10869 // ---------------------------------------------------------------------------
10870 
10871 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
10872 /*
10873  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
10874  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
10875 */
10876 {
10877  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
10878  LeadingPoints = false;
10879  if(PrefDirVector.empty())
10880  {
10881  Utilities->CallLogPop(1786);
10882  return false; // should never be empty but allow for it for safety
10883  }
10884  if(PrefDirVector.size() == 1)
10885  {
10886  Utilities->CallLogPop(149);
10887  return false; // can't end if only one element
10888  }
10889 /*
10890  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
10891  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
10892  {
10893  Utilities->CallLogPop(150);
10894  return true;
10895  }
10896 */
10897 // allow for anything but leading points
10898  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
10899  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
10900  {
10901  Utilities->CallLogPop(1776);
10902  return true;
10903  }
10904  else
10905  {
10906  LeadingPoints = true;
10907  Utilities->CallLogPop(151);
10908  return false;
10909  }
10910 }
10911 
10912 // ---------------------------------------------------------------------------
10913 
10915 /*
10916  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
10917  and that every element is connected to the next element
10918 */
10919 {
10920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
10921  int Position;
10922  AnsiString ErrorString;
10923  bool Error = false;
10924 
10925  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
10926  {
10927  if(PrefDirVector.at(x).HLoc == -2000000000)
10928  {
10929  Error = true;
10930  ErrorString = "HLoc";
10931  Position = x;
10932  }
10933  if(PrefDirVector.at(x).VLoc == -2000000000)
10934  {
10935  Error = true;
10936  ErrorString = "VLoc";
10937  Position = x;
10938  }
10939  if(PrefDirVector.at(x).ELink == -1)
10940  {
10941  Error = true;
10942  ErrorString = "ELink";
10943  Position = x;
10944  }
10945  if(PrefDirVector.at(x).ELinkPos == -1)
10946  {
10947  Error = true;
10948  ErrorString = "ELinkPos";
10949  Position = x;
10950  }
10951  if(PrefDirVector.at(x).XLink == -1)
10952  {
10953  Error = true;
10954  ErrorString = "XLink";
10955  Position = x;
10956  }
10957  if(PrefDirVector.at(x).XLinkPos == -1)
10958  {
10959  Error = true;
10960  ErrorString = "XLinkPos";
10961  Position = x;
10962  }
10963  if(PrefDirVector.at(x).SpeedTag == 0)
10964  {
10965  Error = true;
10966  ErrorString = "Tag";
10967  Position = x;
10968  }
10969  if(PrefDirVector.at(x).TrackVectorPosition == -1)
10970  {
10971  Error = true;
10972  ErrorString = "TrackVectorPosition";
10973  Position = x;
10974  }
10975  if(PrefDirVector.at(x).EXNumber == -1)
10976  {
10977  Error = true;
10978  ErrorString = "EXNumber";
10979  Position = x;
10980  }
10981  if(PrefDirVector.at(x).CheckCount != 9)
10982  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
10983  {
10984  Error = true;
10985  ErrorString = "CheckCount";
10986  Position = x;
10987  }
10988 // extra checks
10989  if(PrefDirVector.at(x).EXGraphicPtr == 0)
10990  {
10991  Error = true;
10992  ErrorString = "EntryGraphicPtr";
10993  Position = x;
10994  }
10995  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
10996  {
10997  Error = true;
10998  ErrorString = "EntryDirectionGraphicPtr";
10999  Position = x;
11000  }
11001 // end of extra checks
11002  if(x > 0)
11003  {
11004  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
11005  {
11006  Error = true;
11007  ErrorString = "Last XLink not connected to this element";
11008  Position = x;
11009  }
11010  }
11011  }
11012  if(Error)
11013  {
11014  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
11015  }
11016  else
11017  {
11018  Utilities->CallLogPop(153);
11019  return true;
11020  }
11021 }
11022 
11023 // ---------------------------------------------------------------------------
11024 
11025 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
11026 /*
11027  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
11028  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
11029  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
11030  or a leading point.
11031 */
11032 {
11033  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11034  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
11035  {
11036  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
11037  {
11038  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
11039  {
11040  ErasePrefDirElementAt(1, PrefDirVecPos);
11041  }
11042  if(PrefDirVector.size() == 0)
11043  {
11044  Utilities->CallLogPop(154);
11045  return true;
11046  }
11047  if(PrefDirVector.size() == 1)
11048  {
11049  PrefDirVector.at(x - 1).ELinkPos = -1;
11050  PrefDirVector.at(x - 1).ELink = -1;
11051  PrefDirVector.at(x - 1).XLinkPos = -1;
11052  PrefDirVector.at(x - 1).XLink = -1;
11053  PrefDirVector.at(x - 1).EXNumber = -1;
11054  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
11055  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
11056  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
11057  Utilities->CallLogPop(155);
11058  return true;
11059  }
11060  // here with truncate element not first element, so ELink & ELinkPos set
11061  // unset XLink & Pos if a leading point
11062  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
11063  {
11064  PrefDirVector.at(x - 1).XLinkPos = -1;
11065  PrefDirVector.at(x - 1).XLink = -1;
11066  PrefDirVector.at(x - 1).EXNumber = -1;
11067  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
11068  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
11069  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
11070  Utilities->CallLogPop(156);
11071  return true;
11072  }
11073  Utilities->CallLogPop(157);
11074  return true;
11075  }
11076  }
11077  Utilities->CallLogPop(158);
11078  return false;
11079 }
11080 
11081 // ---------------------------------------------------------------------------
11082 
11083 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
11084  const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
11085 /*
11086  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
11087  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
11088  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
11089  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
11090  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
11091  displayed.
11092 */
11093 {
11094  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
11095  AnsiString((short)BuildingPrefDir));
11096  int HPos, VPos;
11097 
11098  if(PrefDirSize() == 0)
11099  {
11100  Utilities->CallLogPop(159);
11101  return;
11102  }
11103  for(unsigned int x = 0; x < PrefDirSize(); x++)
11104  {
11105  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
11106 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
11107 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
11108 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
11109  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
11110  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
11111  // only the front half of which will be overplotted by the back of the train, then when the train is
11112  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
11113  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
11114  {
11115  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
11116  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
11117  {
11118  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11119  }
11120  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
11121  // Route, no direction if a single element
11122  {
11123  if(x == 0)
11124  {
11125  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11126  }
11127  if(x == (PrefDirSize() - 1))
11128  {
11129  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
11130  }
11131  }
11132  }
11133  }
11134 
11135 // set start & end element colours if building a PrefDir
11136  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
11137  {
11138  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
11139  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
11140  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
11141  // set last element colour
11142  if(PrefDirSize() > 1)
11143  {
11144  unsigned int LatestPos = PrefDirSize() - 1;
11145  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
11146  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
11147  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
11148  }
11149  }
11150  Disp->Update();
11151  Utilities->CallLogPop(160);
11152 }
11153 
11154 // ---------------------------------------------------------------------------
11155 
11157 /*
11158  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
11159  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
11160 */
11161 {
11162  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
11163  if(PrefDirSize() == 0)
11164  {
11165  Utilities->CallLogPop(1547);
11166  return;
11167  }
11168 
11169  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11170  bool FoundFlag;
11172  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
11173 
11174  while(MMIT != PrefDir4MultiMap.end())
11175  {
11176  H = MMIT->first.first;
11177  V = MMIT->first.second;
11178  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11179  // always found in order, any missing have PrefDirPosx == -1
11180  if(PrefDirPos0 > -1)
11181  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
11182  if(PrefDirPos1 > -1)
11183  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
11184  if(PrefDirPos2 > -1)
11185  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
11186  if(PrefDirPos3 > -1)
11187  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
11188  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
11189  { // need to plot all 4 in order to obtain all the direction graphics
11190  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11191  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11192  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11193  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11194  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11195  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11196  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
11197  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
11198  MMIT++;
11199  MMIT++;
11200  MMIT++;
11201  MMIT++;
11202  }
11203  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
11204  {
11205  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11206  { // 0 & 1 constitute the bidirectional PrefDir
11207  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
11208  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
11209  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11210  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11211  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11212  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11213  MMIT++;
11214  MMIT++;
11215  MMIT++;
11216  }
11217  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
11218  { // 0 & 2 constitute the bidirectional PrefDir
11219  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11220  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11221  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11222  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11223  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11224  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11225  MMIT++;
11226  MMIT++;
11227  MMIT++;
11228  }
11229  else
11230  { // 1 & 2 constitute the bidirectional PrefDir
11231  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11232  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11233  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11234  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11235  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
11236  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
11237  MMIT++;
11238  MMIT++;
11239  MMIT++;
11240  }
11241  }
11242  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
11243  {
11244  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
11245  { // 0 & 1 constitute the bidirectional PrefDir
11246  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
11247  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
11248  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
11249  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
11250  MMIT++;
11251  MMIT++;
11252  }
11253  else
11254  { // 2 unidirectional PrefDirs
11255  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11256  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11257  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
11258  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
11259  MMIT++;
11260  MMIT++;
11261  }
11262  }
11263  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
11264  {
11265  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
11266  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
11267  MMIT++;
11268  }
11269  }
11270  Disp->Update();
11271  Utilities->CallLogPop(1548);
11272 }
11273 
11274 // ---------------------------------------------------------------------------
11275 
11276 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
11277 {
11278  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
11279  int TempInt;
11280 
11281  ClearPrefDir();
11282  int NumberOfPrefDirElements = 0;
11283 
11284  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11285  for(int x = 0; x < NumberOfPrefDirElements; x++)
11286  {
11287  VecFile >> TempInt; // TrackVectorPosition
11288  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
11289  LoadPrefDirElement.TrackVectorPosition = TempInt;
11290  VecFile >> TempInt;
11291  LoadPrefDirElement.ELink = TempInt;
11292  VecFile >> TempInt;
11293  LoadPrefDirElement.ELinkPos = TempInt;
11294  VecFile >> TempInt;
11295  LoadPrefDirElement.XLink = TempInt;
11296  VecFile >> TempInt;
11297  LoadPrefDirElement.XLinkPos = TempInt;
11298  VecFile >> TempInt;
11299  LoadPrefDirElement.EXNumber = TempInt;
11300  VecFile >> TempInt;
11301  LoadPrefDirElement.CheckCount = TempInt;
11302  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
11303  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
11304  LoadPrefDirElement.ConsecSignals = Utilities->LoadFileBool(VecFile);
11305  if(!(LoadPrefDirElement.IsARoute))
11306  {
11307  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
11308  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
11309  }
11310  else
11311  {
11312  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.ConsecSignals);
11313  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
11314  LoadPrefDirElement.ConsecSignals);
11315  }
11316  StorePrefDirElement(5, LoadPrefDirElement);
11317  Utilities->LoadFileString(VecFile); // marker
11318  }
11320  Utilities->CallLogPop(161);
11321 }
11322 
11323 // ---------------------------------------------------------------------------
11324 
11325 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
11326 {
11327  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
11328  int TempInt;
11329 
11330  ClearPrefDir();
11331  int NumberOfPrefDirElements = 0;
11332 
11333  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11334  for(int x = 0; x < NumberOfPrefDirElements; x++)
11335  {
11336  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
11337  VecFile >> TempInt; // TrackVectorPosition
11338  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt));
11339  LoadPrefDirElement.TrackVectorPosition = TempInt;
11340  VecFile >> TempInt;
11341  LoadPrefDirElement.ELink = TempInt;
11342  VecFile >> TempInt;
11343  LoadPrefDirElement.ELinkPos = TempInt;
11344  VecFile >> TempInt;
11345  LoadPrefDirElement.XLink = TempInt;
11346  VecFile >> TempInt;
11347  LoadPrefDirElement.XLinkPos = TempInt;
11348  VecFile >> TempInt;
11349  LoadPrefDirElement.EXNumber = TempInt;
11350  VecFile >> TempInt;
11351  LoadPrefDirElement.CheckCount = TempInt;
11352  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
11353  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
11354  LoadPrefDirElement.ConsecSignals = Utilities->LoadFileBool(VecFile);
11355  if(!(LoadPrefDirElement.IsARoute))
11356  {
11357  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
11358  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
11359  }
11360  else
11361  {
11362  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.ConsecSignals);
11363  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
11364  LoadPrefDirElement.ConsecSignals);
11365  }
11366  StorePrefDirElement(0, LoadPrefDirElement);
11367  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
11368  }
11370  Utilities->CallLogPop(1509);
11371 }
11372 
11373 // ---------------------------------------------------------------------------
11374 
11375 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
11376 /*
11377  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
11378  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
11379 */
11380 {
11381  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
11382  int TempInt;
11383  int NumberOfPrefDirElements = 0;
11384 
11385  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
11386  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
11387  {
11388  Utilities->CallLogPop(1152);
11389  return false;
11390  }
11391  for(int x = 0; x < NumberOfPrefDirElements; x++)
11392  {
11393  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
11394  {
11395  Utilities->CallLogPop(1766);
11396  return false;
11397  }
11398  VecFile >> TempInt;
11399  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
11400  {
11401  Utilities->CallLogPop(163);
11402  return false;
11403  }
11404  VecFile >> TempInt;
11405  if((TempInt < -1) || (TempInt > 9)) // ELink
11406  {
11407  Utilities->CallLogPop(162);
11408  return false;
11409  }
11410  VecFile >> TempInt;
11411  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
11412  {
11413  Utilities->CallLogPop(164);
11414  return false;
11415  }
11416  VecFile >> TempInt;
11417  if((TempInt < -1) || (TempInt > 9)) // XLink
11418  {
11419  Utilities->CallLogPop(165);
11420  return false;
11421  }
11422  VecFile >> TempInt;
11423  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
11424  {
11425  Utilities->CallLogPop(166);
11426  return false;
11427  }
11428  VecFile >> TempInt;
11429  if((TempInt < -1) || (TempInt > 27)) // EXNumber
11430  {
11431  Utilities->CallLogPop(167);
11432  return false;
11433  }
11434  VecFile >> TempInt;
11435  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
11436  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
11437  // ELinkPos, XLink, XLinkPos & EXNumber
11438  {
11439  Utilities->CallLogPop(168);
11440  return false;
11441  }
11442  VecFile >> TempInt;
11443  if((TempInt != 0) && (TempInt != 1)) // RouteElement
11444  {
11445  Utilities->CallLogPop(1147);
11446  return false;
11447  }
11448  VecFile >> TempInt;
11449  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
11450  {
11451  Utilities->CallLogPop(1510);
11452  return false;
11453  }
11454  VecFile >> TempInt;
11455  if((TempInt != 0) && (TempInt != 1)) // ConsecSignals
11456  {
11457  Utilities->CallLogPop(1148);
11458  return false;
11459  }
11460  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
11461  {
11462  Utilities->CallLogPop(1700);
11463  return false;
11464  }
11465  }
11466  Utilities->CallLogPop(169);
11467  return true;
11468 }
11469 
11470 // ---------------------------------------------------------------------------
11471 
11472 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
11473 {
11474  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
11475  int NumberOfPrefDirElements = PrefDirVector.size();
11476 
11477  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
11478  for(int y = 0; y < NumberOfPrefDirElements; y++)
11479  {
11480  VecFile << y << '\n'; // extra
11481  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n';
11482  VecFile << PrefDirVector.at(y).ELink << '\n';
11483  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
11484  VecFile << PrefDirVector.at(y).XLink << '\n';
11485  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
11486  VecFile << PrefDirVector.at(y).EXNumber << '\n';
11487  VecFile << PrefDirVector.at(y).CheckCount << '\n';
11488  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
11489  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
11490  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).ConsecSignals);
11491  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
11492  {
11493  VecFile << "************" << '\0' << '\n'; // marker
11494  }
11495  else
11496  {
11497  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11498  }
11499  }
11500  Utilities->CallLogPop(170);
11501 }
11502 
11503 // ---------------------------------------------------------------------------
11504 
11505 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
11506 {
11507  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
11508  int NumberOfSearchElements = SearchVector.size();
11509 
11510  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
11511  for(int y = 0; y < NumberOfSearchElements; y++)
11512  {
11513  VecFile << y << '\n'; // extra
11514  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
11515  VecFile << SearchVector.at(y).ELink << '\n';
11516  VecFile << SearchVector.at(y).ELinkPos << '\n';
11517  VecFile << SearchVector.at(y).XLink << '\n';
11518  VecFile << SearchVector.at(y).XLinkPos << '\n';
11519  VecFile << SearchVector.at(y).EXNumber << '\n';
11520  VecFile << SearchVector.at(y).CheckCount << '\n';
11521  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
11522  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
11523  Utilities->SaveFileBool(VecFile, SearchVector.at(y).ConsecSignals);
11524  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
11525  {
11526  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11527  }
11528  else
11529  {
11530  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
11531  }
11532  }
11533  Utilities->CallLogPop(1847);
11534 }
11535 
11536 // ---------------------------------------------------------------------------
11537 
11538 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
11539 /*
11540  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
11541  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
11542 */
11543 {
11544  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
11545  AnsiString(VLoc));
11546  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
11547 
11548  if(VecPos > -1)
11549  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
11550  else
11551  {
11552  Utilities->CallLogPop(171);
11553  return;
11554  }
11555  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
11556  if(VecPos > -1)
11557  ErasePrefDirElementAt(3, VecPos);
11558  else
11559  {
11560  Utilities->CallLogPop(172);
11561  return;
11562  }
11563  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
11564  if(VecPos > -1)
11565  ErasePrefDirElementAt(4, VecPos);
11566  else
11567  {
11568  Utilities->CallLogPop(173);
11569  return;
11570  }
11571  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
11572  if(VecPos > -1)
11573  ErasePrefDirElementAt(5, VecPos);
11574  else
11575  {
11576  Utilities->CallLogPop(174);
11577  return;
11578  }
11579  Utilities->CallLogPop(175);
11580 }
11581 
11582 // ---------------------------------------------------------------------------
11583 /*
11584  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
11585  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
11586 
11587  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
11588  in their place so that existing linkages will be preserved. At this stage this function is called to remove
11589  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
11590  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
11591  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
11592  PrefDirVector to correspond to the new track layout.
11593 
11594  {
11595  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
11596  if(PrefDirSize() == 0)
11597  {
11598  Utilities->CallLogPop(176);
11599  return;
11600  }
11601  for(int x=(PrefDirVector.size()-1);x>=0;x--)
11602  {
11603  int TV = PrefDirVector.at(x).TrackVectorPosition;
11604  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
11605  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
11606  if(Track->BlankElementAt(0, TV))
11607  {
11608  ErasePrefDirElementAt(6, x);
11609  }
11610  //if was a blankelement at x then ConnELink and ConnXLink both -1
11611  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
11612  {
11613  ErasePrefDirElementAt(7, x);
11614  }
11615  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
11616  //needs to be erased once, but if don't use 'else' then will erase two elements
11617  //since 'x' will correspond to the element after the first erased element
11618  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
11619  {
11620  ErasePrefDirElementAt(8, x);
11621  }
11622  }
11623  Utilities->CallLogPop(177);
11624  }
11625 */
11626 // ---------------------------------------------------------------------------
11627 
11628 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
11629 /*
11630  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
11631  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
11632 */
11633 {
11634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
11635  bool AlreadyPresent, FoundFlag;
11636  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
11637 
11638  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
11639  {
11640  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
11641  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
11642  AlreadyPresent = false;
11643  if(FoundFlag)
11644  {
11645  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
11646  AlreadyPresent = true;
11647  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
11648  AlreadyPresent = true;
11649  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
11650  AlreadyPresent = true;
11651  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
11652  AlreadyPresent = true;
11653  }
11654  if(!AlreadyPresent)
11655  StorePrefDirElement(4, TempElement);
11656  }
11658  Utilities->CallLogPop(178);
11659 }
11660 /* earlier brute force search
11661  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
11662  {
11663  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
11664  bool AlreadyPresent = false;
11665  for(unsigned int y = 0;y<PrefDirSize();y++)
11666  {
11667  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
11668  }
11669  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
11670  }
11671 */
11672 
11673 // ---------------------------------------------------------------------------
11674 
11676 /*
11677  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
11678  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
11679  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
11680  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
11681  positions are likely to have changed, so this function is called to reset all the necessary connections and
11682  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
11683  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
11684  shouldn't have changed.
11685 */
11686 {
11687  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
11688  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11689  {
11690  bool FoundFlag;
11691  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11692  if(FoundFlag)
11693  {
11694  PrefDirVector.at(x).TrackVectorPosition = VecPos;
11695  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
11696  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
11697  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
11698  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
11699  for(unsigned int z = 0; z < 4; z++)
11700  {
11701  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
11702  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
11703  }
11704  }
11705  else
11706  {
11707  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
11708  }
11709  }
11710  Utilities->CallLogPop(179);
11711 }
11712 
11713 // ---------------------------------------------------------------------------
11714 
11716 /*
11717  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
11718 */
11719 {
11720  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
11721  bool DiscrepancyFound = false;
11722 
11723  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11724  {
11725  bool FoundFlag;
11726  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11727  if(FoundFlag)
11728  {
11729  TPrefDirElement PE = PrefDirVector.at(x);
11730  if(PE.TrackVectorPosition != VecPos)
11731  DiscrepancyFound = true;
11732  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11733  {
11734  DiscrepancyFound = true;
11735  break;
11736  }
11737  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11738  {
11739  DiscrepancyFound = true;
11740  break;
11741  }
11742  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
11743  {
11744  DiscrepancyFound = true;
11745  break;
11746  }
11747  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
11748  {
11749  DiscrepancyFound = true;
11750  break;
11751  }
11752  }
11753  else
11754  DiscrepancyFound = true;
11755  }
11756  if(DiscrepancyFound)
11757  {
11758  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
11759  ClearPrefDir(); // also clears multimap
11760  }
11761  Utilities->CallLogPop(1436);
11762 }
11763 
11764 // ---------------------------------------------------------------------------
11765 
11767 /*
11768  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
11769  return true for OK
11770 */
11771 {
11772  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
11773  bool DiscrepancyFound = false;
11774 
11775  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11776  {
11777  bool FoundFlag;
11778  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
11779  if(FoundFlag)
11780  {
11781  TPrefDirElement PE = PrefDirVector.at(x);
11782  if(PE.TrackVectorPosition != VecPos)
11783  DiscrepancyFound = true;
11784  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
11785  {
11786  DiscrepancyFound = true;
11787  break;
11788  }
11789  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
11790  {
11791  DiscrepancyFound = true;
11792  break;
11793  }
11794  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
11795  {
11796  DiscrepancyFound = true;
11797  break;
11798  }
11799  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
11800  {
11801  DiscrepancyFound = true;
11802  break;
11803  }
11804  }
11805  else
11806  DiscrepancyFound = true;
11807  }
11808  Utilities->CallLogPop(1512);
11809  return !DiscrepancyFound;
11810 }
11811 
11812 // ---------------------------------------------------------------------------
11813 
11814 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
11815 /*
11816  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
11817  turn and for the overall sizes.
11818 */
11819 {
11820  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
11821  bool FoundFlag = false;
11822  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
11823 
11824  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
11825  {
11826  TPrefDirElement CheckElement = PrefDirVector.at(a);
11827  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
11828  if(!FoundFlag)
11829  {
11830  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
11831  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
11832  }
11833  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
11834  {
11835  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
11836  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
11837  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
11838  }
11839  }
11840  if(PrefDirVector.size() != PrefDir4MultiMap.size())
11841  {
11842  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
11843  + " Caller=" + (AnsiString)Caller);
11844  }
11845  Utilities->CallLogPop(180);
11846 }
11847 
11848 // ---------------------------------------------------------------------------
11849 
11850 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
11851  int &PrefDirPos3)
11852 /*
11853  There are up to four elements at each H & V position in the PrefDirVector - two directions, and up to
11854  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
11855  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
11856  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
11857  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
11858 */
11859 {
11860  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
11861  AnsiString(VLoc));
11862  THVPair PrefDirMapKeyPair;
11863 
11864  PrefDirPos0 = -1;
11865  PrefDirPos1 = -1;
11866  PrefDirPos2 = -1;
11867  PrefDirPos3 = -1;
11868  FoundFlag = false;
11869  PrefDirMapKeyPair.first = HLoc;
11870  PrefDirMapKeyPair.second = VLoc;
11871  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
11872 
11873  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
11874  if(ItPair.first == ItPair.second)
11875  {
11876  Utilities->CallLogPop(181);
11877  return;
11878  }
11879  else
11880  {
11881  FoundFlag = true;
11882  PrefDirPos0 = ItPair.first->second;
11883  ItPair.first++;
11884  if(ItPair.first == ItPair.second)
11885  {
11886  Utilities->CallLogPop(182);
11887  return;
11888  }
11889  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11890  PrefDirPos1 = ItPair.first->second;
11891  ItPair.first++;
11892  if(ItPair.first == ItPair.second)
11893  {
11894  Utilities->CallLogPop(183);
11895  return;
11896  }
11897  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11898  PrefDirPos2 = ItPair.first->second;
11899  ItPair.first++;
11900  if(ItPair.first == ItPair.second)
11901  {
11902  Utilities->CallLogPop(184);
11903  return;
11904  }
11905  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
11906  PrefDirPos3 = ItPair.first->second;
11907  }
11908  Utilities->CallLogPop(185);
11909 }
11910 
11911 // ---------------------------------------------------------------------------
11912 
11913 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
11914 /*
11915  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
11916 */
11917 {
11918  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
11919  PrefDirVector.push_back(LoadPrefDirElement);
11920  THVPair PrefDir4MultiMapKeyPair;
11921  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
11922 
11923  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
11924  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
11925  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
11926  PrefDir4MultiMapEntry.second = LastElementNumber(68);
11927  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
11928 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
11929  Utilities->CallLogPop(186);
11930 }
11931 
11932 // ---------------------------------------------------------------------------
11933 
11934 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
11935 /*
11936  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
11937  4MultiMap if they are greater than the erased value.
11938 */
11939 {
11940  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
11941  bool FoundFlag;
11942 
11943  if(!PrefDirVector.empty())
11944  {
11945  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
11946  if(!FoundFlag)
11947  {
11948  throw Exception("Failed to find PrefDir4MultiMap erase element");
11949  }
11950  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
11951  PrefDir4MultiMap.erase(EraseIt);
11952  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
11954  }
11955  Utilities->CallLogPop(187);
11956 }
11957 
11958 // ---------------------------------------------------------------------------
11959 
11960 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
11961 /*
11962  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
11963  4MultiMap if they are greater than the erased value.
11964 */
11965 {
11966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
11967  AnsiString(ErasedElementNumber));
11968  if(!PrefDir4MultiMap.empty())
11969  {
11970  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
11971  {
11972  if(MapPtr->second > ErasedElementNumber)
11973  MapPtr->second--;
11974  }
11975  }
11976  Utilities->CallLogPop(1450);
11977 }
11978 
11979 // ---------------------------------------------------------------------------
11980 
11981 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
11982 /*
11983  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
11984  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
11985  nothing is found this is an error but the error message is given in the calling function.
11986 */
11987 {
11988  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
11989  FoundFlag = false;
11990  if(PrefDirVectorPosition >= PrefDirVector.size())
11991  {
11992  throw Exception("PrefDirVectorPosition out of range");
11993  }
11994  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
11995  THVPair PrefDir4MultiMapKeyPair;
11996 
11997  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
11998  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
11999  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12000 
12001  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
12002  if(ItPair.first == ItPair.second)
12003  {
12004  Utilities->CallLogPop(188);
12005  return ItPair.first; // nothing found but have to return an iterator, FoundFlag indicates nothing found
12006  }
12007  else
12008  {
12009  if(ItPair.first->second == PrefDirVectorPosition)
12010  {
12011  FoundFlag = true;
12012  Utilities->CallLogPop(189);
12013  return ItPair.first;
12014  }
12015  ItPair.first++;
12016  if(ItPair.first == ItPair.second)
12017  {
12018  Utilities->CallLogPop(190);
12019  return ItPair.first; // nothing found
12020  }
12021  if(ItPair.first->second == PrefDirVectorPosition)
12022  {
12023  FoundFlag = true;
12024  Utilities->CallLogPop(191);
12025  return ItPair.first;
12026  }
12027  ItPair.first++;
12028  if(ItPair.first == ItPair.second)
12029  {
12030  Utilities->CallLogPop(192);
12031  return ItPair.first; // nothing found
12032  }
12033  if(ItPair.first->second == PrefDirVectorPosition)
12034  {
12035  FoundFlag = true;
12036  Utilities->CallLogPop(193);
12037  return ItPair.first;
12038  }
12039  ItPair.first++;
12040  if(ItPair.first == ItPair.second)
12041  {
12042  Utilities->CallLogPop(194);
12043  return ItPair.first; // nothing found
12044  }
12045  if(ItPair.first->second == PrefDirVectorPosition)
12046  {
12047  FoundFlag = true;
12048  Utilities->CallLogPop(195);
12049  return ItPair.first;
12050  }
12051  }
12052  Utilities->CallLogPop(196);
12053  return ItPair.first; // nothing found
12054 }
12055 
12056 // ---------------------------------------------------------------------------
12057 
12058 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
12059 /*
12060  Although there may be up to four entries at one H & V position this function gets just one. It is
12061  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
12062  at H & V.
12063 */
12064 {
12065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12066  THVPair PrefDir4MultiMapKeyPair;
12067 
12068  PrefDir4MultiMapKeyPair.first = HLoc;
12069  PrefDir4MultiMapKeyPair.second = VLoc;
12070  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12071 
12072  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
12073  if(ItPair.first == ItPair.second) // nothing found
12074  {
12075  Utilities->CallLogPop(197);
12076  return -1;
12077  }
12078  else
12079  {
12080  Utilities->CallLogPop(198);
12081  return ItPair.first->second;
12082  }
12083 }
12084 
12085 // ---------------------------------------------------------------------------
12086 
12087 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
12088 {
12089  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
12090  bool ErasedFlag = false;
12091 
12092  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
12093  {
12094  if(PrefDirSize() == 0)
12095  {
12096  Utilities->CallLogPop(1511);
12097  return;
12098  }
12099  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
12100  {
12101  ErasedFlag = false;
12102  // use 'else' to ensure don't try to access an erased element
12103  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
12104  {
12105  ErasePrefDirElementAt(11, x);
12106  ErasedFlag = true;
12107  }
12108  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
12109  {
12110  ErasePrefDirElementAt(12, x);
12111  ErasedFlag = true;
12112  }
12113  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
12114  {
12115  ErasePrefDirElementAt(13, x);
12116  ErasedFlag = true;
12117  }
12118  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
12119  {
12120  ErasePrefDirElementAt(9, x);
12121  ErasedFlag = true;
12122  }
12123  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
12124  {
12125  ErasePrefDirElementAt(10, x);
12126  ErasedFlag = true;
12127  }
12128  if(!ErasedFlag)
12129  {
12130  // don't use 'else' here as may be more than one that need decrementing
12131  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
12132  {
12133  PrefDirVector.at(x).TrackVectorPosition--;
12134  }
12135  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
12136  {
12137  PrefDirVector.at(x).Conn[0]--;
12138  }
12139  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
12140  {
12141  PrefDirVector.at(x).Conn[1]--;
12142  }
12143  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
12144  {
12145  PrefDirVector.at(x).Conn[2]--;
12146  }
12147  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
12148  {
12149  PrefDirVector.at(x).Conn[3]--;
12150  }
12151  }
12152  }
12153  }
12154  Utilities->CallLogPop(1434);
12155 }
12156 
12157 // ---------------------------------------------------------------------------
12158 
12159 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
12160 {
12161  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
12162  OverallDistance = 0;
12163  OverallSpeedLimit = 0;
12164  LeadingPointsAtLastElement = false;
12165  if(PrefDirSize() == 0) // shouldn't be empty when this called
12166  {
12167  Utilities->CallLogPop(1491);
12168  return;
12169  }
12170 
12171  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
12172  {
12173  LeadingPointsAtLastElement = true;
12174  Utilities->CallLogPop(1492);
12175  return;
12176  }
12177  for(unsigned int x = 0; x < PrefDirSize(); x++)
12178  {
12179  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
12180  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
12181  {
12182  OverallDistance += PrefDirElement.Length23;
12183  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
12184  {
12185  if(x == 0)
12186  {
12187  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
12188  }
12189  else
12190  {
12191  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
12192  {
12193  OverallSpeedLimit = -1;
12194  }
12195  }
12196  }
12197  }
12198  else
12199  {
12200  OverallDistance += PrefDirElement.Length01;
12201  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
12202  {
12203  if(x == 0)
12204  {
12205  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
12206  }
12207  else
12208  {
12209  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
12210  {
12211  OverallSpeedLimit = -1;
12212  }
12213  }
12214  }
12215  }
12216  }
12217  Utilities->CallLogPop(1529);
12218 }
12219 
12220 // ---------------------------------------------------------------------------
12221 
12222 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
12223 {
12224  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
12225  if(PrefDirSize() == 0)
12226  {
12227  Utilities->CallLogPop(1564);
12228  return;
12229  }
12230 
12231  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12232  bool FoundFlag;
12234  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12235 
12236  while(MMIT != PrefDir4MultiMap.end())
12237  {
12238  HLoc = MMIT->first.first;
12239  VLoc = MMIT->first.second;
12240  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12241  H = HLoc - Track->GetHLocMin();
12242  V = VLoc - Track->GetVLocMin();
12243  // always found in order, any missing have PrefDirPosx == -1
12244  if(PrefDirPos0 > -1)
12245  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12246  if(PrefDirPos1 > -1)
12247  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
12248  if(PrefDirPos2 > -1)
12249  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
12250  if(PrefDirPos3 > -1)
12251  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
12252  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12253  { // need to plot all 4 in order to obtain all the direction graphics
12254  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12255  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12256  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12257  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12258  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12259  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12260  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12261  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12262  MMIT++;
12263  MMIT++;
12264  MMIT++;
12265  MMIT++;
12266  }
12267  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12268  {
12269  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12270  { // 0 & 1 constitute the bidirectional PrefDir
12271  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12272  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12273  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12274  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12275  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12276  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12277  MMIT++;
12278  MMIT++;
12279  MMIT++;
12280  }
12281  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12282  { // 0 & 2 constitute the bidirectional PrefDir
12283  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12284  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12285  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12286  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12287  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12288  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12289  MMIT++;
12290  MMIT++;
12291  MMIT++;
12292  }
12293  else
12294  { // 1 & 2 constitute the bidirectional PrefDir
12295  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12296  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12297  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12298  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12299  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12300  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12301  MMIT++;
12302  MMIT++;
12303  MMIT++;
12304  }
12305  }
12306  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12307  {
12308  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12309  { // 0 & 1 constitute the bidirectional PrefDir
12310  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12311  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12312  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12313  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12314  MMIT++;
12315  MMIT++;
12316  }
12317  else
12318  { // 2 unidirectional PrefDirs
12319  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12320  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12321  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12322  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12323  MMIT++;
12324  MMIT++;
12325  }
12326  }
12327  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12328  {
12329  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12330  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12331  MMIT++;
12332  }
12333  }
12334  Utilities->CallLogPop(1565);
12335 }
12336 
12337 // ---------------------------------------------------------------------------
12338 
12339 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
12340 /*
12341  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
12342  level crossing, signals with wrong direction set, or buffers.
12343 */
12344 {
12345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
12346  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12347  bool FoundFlag;
12349  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12350 
12351  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
12352  ElementIn.VLoc)))
12353  {
12354  Utilities->CallLogPop(1982);
12355  return false;
12356  }
12357  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
12358  {
12359  Utilities->CallLogPop(1983);
12360  return false;
12361  }
12362  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
12363  {
12364  Utilities->CallLogPop(1995);
12365  return false;
12366  }
12367 // Now check that there is only a single prefdir set
12368  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12369 // always found in order, any missing have PrefDirPosx == -1
12370  if(PrefDirPos0 > -1)
12371  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12372  if(PrefDirPos1 > -1)
12373  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
12374  if(PrefDirPos2 > -1)
12375  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
12376  if(PrefDirPos3 > -1)
12377  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
12378 
12379  if(PrefDirPos3 > -1) // 4 found, all bidirectional
12380  {
12381  Utilities->CallLogPop(1984);
12382  return false;
12383  }
12384  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12385  {
12386  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
12387  {
12388  Utilities->CallLogPop(1985);
12389  return false;
12390  }
12391  else
12392  {
12393  Utilities->CallLogPop(1986);
12394  return true;
12395  }
12396  }
12397  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12398  {
12399  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
12400  {
12401  Utilities->CallLogPop(1987);
12402  return false;
12403  }
12404  else
12405  {
12406  Utilities->CallLogPop(1988);
12407  return true;
12408  }
12409  }
12410  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
12411  {
12412  if(PrefDirElement0.XLinkPos == EntryPos)
12413  {
12414  Utilities->CallLogPop(1989);
12415  return false;
12416  }
12417  else
12418  {
12419  Utilities->CallLogPop(1990);
12420  return true;
12421  }
12422  }
12423  else
12424  {
12425  Utilities->CallLogPop(1991);
12426  return false; // none found
12427  }
12428 }
12429 
12430 // ---------------------------------------------------------------------------
12431 
12433 {
12434 /* //Added at v2.1.0
12435  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
12436  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
12437  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
12438  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
12439  and can be modelled better anyway.
12440 
12441  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
12442  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
12443  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12444  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12445  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12446  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12447 */
12448  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
12449  ElementIn.VLoc + "," + XLink);
12450  int TrackVecPos;
12451  bool TrackFoundFlag;
12452  TTrackElement TempTrackElement;
12453 
12454  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
12455  {
12456  Utilities->CallLogPop(2047);
12457  return false;
12458  }
12459 
12460 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12461  if(XLink == 1)
12462  {
12463  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12464  if(TrackFoundFlag)
12465  {
12466  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
12467  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12468  {
12469  Utilities->CallLogPop(2048);
12470  return true;
12471  }
12472  }
12473  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
12474  if(TrackFoundFlag)
12475  {
12476  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
12477  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12478  {
12479  Utilities->CallLogPop(2049);
12480  return true;
12481  }
12482  }
12483  }
12484 
12485 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12486  if(XLink == 3)
12487  {
12488  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12489  if(TrackFoundFlag)
12490  {
12491  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
12492  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12493  {
12494  Utilities->CallLogPop(2050);
12495  return true;
12496  }
12497  }
12498  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
12499  if(TrackFoundFlag)
12500  {
12501  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
12502  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12503  {
12504  Utilities->CallLogPop(2051);
12505  return true;
12506  }
12507  }
12508  }
12509 
12510 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12511  if(XLink == 7)
12512  {
12513  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
12514  if(TrackFoundFlag)
12515  {
12516  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
12517  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
12518  {
12519  Utilities->CallLogPop(2052);
12520  return true;
12521  }
12522  }
12523  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12524  if(TrackFoundFlag)
12525  {
12526  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
12527  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
12528  {
12529  Utilities->CallLogPop(2053);
12530  return true;
12531  }
12532  }
12533  }
12534 
12535 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12536  if(XLink == 9)
12537  {
12538  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
12539  if(TrackFoundFlag)
12540  {
12541  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
12542  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
12543  {
12544  Utilities->CallLogPop(2054);
12545  return true;
12546  }
12547  }
12548  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
12549  if(TrackFoundFlag)
12550  {
12551  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
12552  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
12553  {
12554  Utilities->CallLogPop(2055);
12555  return true;
12556  }
12557  }
12558  }
12559  Utilities->CallLogPop(2056);
12560  return false;
12561 }
12562 
12563 // ---------------------------------------------------------------------------
12564 
12565 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
12566 {
12567 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
12568  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
12569  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
12570  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
12571  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
12572 */
12573  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
12575  bool FoundFlag, ContFlag, FoundElements = false;
12576  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12577  TPrefDirElement NextElement;
12578 
12579  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
12580  {
12581  LastIteratorValue++;
12582  ContFlag = false;
12583  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
12584  continue;
12585  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
12586  continue;
12587 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
12588  // found a potential route start point
12589  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
12590  {
12591  continue;
12592  }
12593  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
12594  {
12595  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
12596  if(PDVIt->TrackType == Continuation)
12597  {
12598  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
12599  {
12600  continue;
12601  }
12602  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
12603  {
12604  continue;
12605  }
12606  }
12607  StartElement = *PDVIt;
12608 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
12609  // diverging track on which there was no pref dir. See below for 2 required changes.
12610  }
12611  else
12612  {
12613  continue;
12614  }
12615  // now track along until find a signal or continuation, checking validity for each element
12616  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
12617  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
12618  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12619  if(PrefDirPos0 == -1) // no continuing prefdir
12620  {
12621  continue;
12622  }
12623  bool NextElementFoundFlag = false;
12624  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12625  {
12626  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
12627  NextElementFoundFlag = true;
12628  }
12629  if(PrefDirPos1 > -1)
12630  {
12631  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12632  {
12633  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
12634  NextElementFoundFlag = true;
12635  }
12636  }
12637  if(PrefDirPos2 > -1)
12638  {
12639  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12640  {
12641  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
12642  NextElementFoundFlag = true;
12643  }
12644  }
12645  if(PrefDirPos3 > -1)
12646  {
12647  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
12648  {
12649  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
12650  NextElementFoundFlag = true;
12651  }
12652  }
12653  if(!NextElementFoundFlag)
12654  {
12655  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12656 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
12657  }
12658  while(true)
12659  {
12660  // check validity
12661  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
12662  {
12663  ContFlag = true;
12664  break;
12665  }
12666  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
12667  {
12668  ContFlag = true;
12669  break;
12670  }
12671  // check if in a route, providing not a signal, as a signal might be at the start of a route
12672  if(NextElement.TrackType != SignalPost)
12673  {
12674  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
12675  {
12676  ContFlag = true;
12677  break;
12678  }
12679  }
12680  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
12681  // can't be a gound signal as would have failed the validity test
12682  {
12683  EndElement = NextElement;
12684  break;
12685  }
12686  // get the next element in the sequence
12687  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
12688  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
12689  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12690  if(PrefDirPos0 == -1) // no continuing prefdir
12691  {
12692  ContFlag = true;
12693  break;
12694  }
12695  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12696  {
12697  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
12698  continue;
12699  }
12700  if(PrefDirPos1 > -1)
12701  {
12702  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12703  {
12704  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
12705  continue;
12706  }
12707  }
12708  if(PrefDirPos2 > -1)
12709  {
12710  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12711  {
12712  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
12713  continue;
12714  }
12715  }
12716  if(PrefDirPos3 > -1)
12717  {
12718  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
12719  {
12720  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
12721  continue;
12722  }
12723  }
12724  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
12725  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
12726  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
12727  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
12728  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
12729  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
12730  {
12731  ContFlag = true;
12732  break;
12733  }
12734  else
12735  {
12736  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
12737  // could drop the bridge test but keep it to show the change history
12738  break;
12739 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
12740  }
12741  }
12742  if(ContFlag)
12743  continue;
12744  // else have start and end elements set & all elements valid, so set up the route segment
12745  FoundElements = true;
12746  break;
12747  }
12748  if(FoundElements)
12749  {
12750  Utilities->CallLogPop(1992);
12751  return true;
12752  }
12753  else
12754  {
12755  Utilities->CallLogPop(1993);
12756  return false;
12757  }
12758 }
12759 
12760 // ---------------------------------------------------------------------------
12761 // TOneRoute
12762 // ---------------------------------------------------------------------------
12763 
12764 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
12765 {
12766 /* General:
12767  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
12768  containing all the new elements to form the route. When complete, the SearchVector is converted into route
12769  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
12770  route will use automatic signals or not.
12771  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
12772  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
12773  elements, so additional work is needed to complete all their members before they are ready for conversion into
12774  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
12775  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
12776  ConvertAndAdd.......
12777 
12778  Note that originally intended to allow preferred routes without consecutive signals, hence ConsecSignalsRoute flag.
12779  Later decided to enforce ConsecSignalsRoute for preferred routes, but left original code as was.
12780 
12781  Specific:
12782 
12783  Function returns true for a valid start element, false, with a message, if not.
12784  ClearRoute to empty both PrefDirVector & SearchVector
12785  Check selection matches a TrackElement & ensure a signal/buffers/continuation if using ConsecSignals,
12786  else disallow points, bridge or crossover.
12787  Disallow if train on element.
12788 
12789  Set default values for parameters that are retained in AllRoutes:-
12790  StartSelectionRouteID = route that selection starts in or adjacent to end of;
12791  StartRoutePosition = trackvectornumber of the element to be used as the start of the route;
12792  StartElement1 = the 1st or only TPrefDirElement of the route start element
12793  StartElement2 = the 2nd (if exists) TPrefDirElement of the start element (can be a max of 2 PrefDirs for
12794  a given selection that isn't points, bridge or crossover;
12795 
12796  Check selection corresponds to at least 1 PrefDir element in EveryPrefDir & set StartElement1 & possibly also 2. If
12797  signal/buffers/continuation for ConsecSignalsRoute, or buffers/continuation for not ConsecSignalsRoute,
12798  ensure the PrefDir corresponds to the direction of the signal or away from the buffers/continuation.
12799  Check if in an existing route. Disallow if start anywhere except at end of the route, if the route end is an 'End'
12800  configuration (nowhere to go), and if the end of the route links forwards into another route.
12801  If these tests passed set StartSelectionRouteID, StartElement1 and StartRoutePosition to correspond to the route end element
12802  and blank StartElement2 (only want to use the route element), then return true.
12803  Check also that doesn't lie in >1 route & give error message if so - should never happen.
12804  Check if adjacent to start or end of an existing route & disallow.
12805  The start element (with AutoSignals member set as AutoSigs flag) is stored in SearchVector, unless an existing route element is to
12806  be used as the start element.
12807 */
12808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
12809  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
12810  ClearRoute();
12811  int TrackVectorPosition;
12812  TTrackElement TrackElement;
12813  TPrefDirElement FirstElement, LastElement;
12814 
12815  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12816  {
12817  Utilities->CallLogPop(199);
12818  return false;
12819  }
12820  if(ConsecSignalsRoute)
12821  {
12822  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
12823  {
12824  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
12825  Utilities->CallLogPop(1996);
12826  return false;
12827  }
12828  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12829  {
12830  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
12831  Utilities->CallLogPop(200);
12832  return false;
12833  }
12834  }
12835  else
12836  {
12837  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
12838  {
12839  TrainController->StopTTClockMessage(8, "Can't select points, bridge or crossover when route building");
12840 // makes later adjacent route checks too complicated
12841  Utilities->CallLogPop(201);
12842  return false;
12843  }
12844  }
12845 
12846  if(Track->IsLCAtHV(18, HLoc, VLoc))
12847  {
12848  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
12849  Utilities->CallLogPop(1909);
12850  return false;
12851  }
12852 
12853 // check if selected a train & disallow if so
12854  if(TrackElement.TrainIDOnElement > -1)
12855  {
12856  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
12857  Utilities->CallLogPop(202);
12858  return false;
12859  }
12860 
12861 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
12862  TPrefDirElement PrefDirElement;
12863  int LockedVectorNumber;
12864 
12865  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
12866  {
12867  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
12868  Utilities->CallLogPop(203);
12869  return false;
12870  }
12871  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
12872  {
12873  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
12874  Utilities->CallLogPop(204);
12875  return false;
12876  }
12877 
12879  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
12880 // signal in an autosig route & follow with a non-autosig route
12881 
12882  TPrefDirElement BlankElement;
12883 
12884  StartElement1 = BlankElement;
12885  StartElement2 = BlankElement;
12886 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
12887  bool InPrefDirFlag = false;
12888 
12889  bool FoundFlag;
12890  int PrefDirPos0 = -1;
12891  int PrefDirPos1 = -1;
12892  int PrefDirPos2 = -1;
12893  int PrefDirPos3 = -1;
12894 
12896  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12897  int PrefDirVecPos[4] =
12898  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
12899 
12900  for(int x = 0; x < 4; x++)
12901  {
12902  int b = PrefDirVecPos[x];
12903  if(b > -1)
12904  {
12905  if(ConsecSignalsRoute)
12906  {
12907  // only allow the appropriate exit route to be searched
12908  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
12909  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
12910  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
12911  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
12912  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
12913  {
12914  InPrefDirFlag = true;
12915  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
12916  if(AutoSigsFlag)
12917  {
12918  StartElement1.AutoSignals = true;
12919  }
12921  StartElement2 = BlankElement;
12922  }
12923  }
12924  else
12925  {
12926  // only allow the appropriate exit route to be searched
12927  // AutoSignals & ConsecSignals stay false for not ConsecSignalsRoute
12928  if(((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(22, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(23,
12929  b).XLinkPos] == Connection)) || ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(24,
12930  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(25, b).XLinkPos] == Connection)))
12931  {
12932  InPrefDirFlag = true;
12933  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(26, b);
12934  StartElement2 = BlankElement;
12935  }
12936  else if((TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
12937  {
12938  InPrefDirFlag = true;
12940  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(27, b);
12941  else
12942  StartElement2 = EveryPrefDir->GetFixedPrefDirElementAt(28, b);
12943  }
12944  }
12945  }
12946  }
12947 
12948  if(!InPrefDirFlag)
12949  {
12951  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
12952  Utilities->CallLogPop(205);
12953  return false;
12954  }
12955 
12956 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
12958  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
12959 
12960  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
12961  {
12962  throw Exception("Selection in two routes - should never happen!");
12963  }
12964 
12965  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
12966  {
12967  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
12968  {
12969  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
12970  Utilities->CallLogPop(206);
12971  return false;
12972  }
12973  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
12974  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
12975  {
12976  TrainController->StopTTClockMessage(14, "No forward connection from this position");
12977  Utilities->CallLogPop(207);
12978  return false;
12979  }
12980  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
12981  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
12982  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
12983  {
12984  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
12985  Utilities->CallLogPop(208);
12986  return false;
12987  }
12988  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
12990  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
12991  if(AutoSigsFlag)
12992  {
12993  StartElement1.AutoSignals = true;
12994  }
12995  if(ConsecSignalsRoute)
12996  {
12998  }
12999  StartElement2 = BlankElement; // only use the route element
13001  Utilities->CallLogPop(209);
13002  return true; // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
13003  }
13004 
13005  else // no route started
13006  {
13007 // check if selected position is adjacent to start or end of an existing route and disallow
13008  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13009  {
13010  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
13011  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
13012  {
13013  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
13014  Utilities->CallLogPop(210);
13015  return false;
13016  }
13017  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
13018  {
13019  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
13020  Utilities->CallLogPop(211);
13021  return false;
13022  }
13023  }
13024 
13025 // check if it's adjacent to end of an an existing route,
13026  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13027  {
13029  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
13030  {
13031  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
13032  Utilities->CallLogPop(212);
13033  return false;
13034  }
13035  }
13036  SearchVector.push_back(StartElement1);
13037  Utilities->CallLogPop(213);
13038  return true;
13039  }
13040 }
13041 
13042 // ---------------------------------------------------------------------------
13043 
13044 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag,
13045  IDInt &ReqPosRouteID, bool &PointsChanged)
13046 
13047 /*
13048  [Note this was written when it was intended to have routes confined to preferred direction elements but with a choice of whether
13049  they had to run from signal to signal (bool ConsecSignalsRoute true), or not (bool ConsecSignalsRoute false), as well as using
13050  automatic signals or not. Since then it was decided only to allow these routes to run from signal to signal, so ConsecSignalsRoute
13051  is always true when this routine is called. The routine could be made much simpler, but has been left as is because it works (at
13052  least it has done so far), and it allows the original option to be used if it ever seems appropriate in the future.]
13053  *
13054  Return true if select valid next element, in which case the route is set & stored. Return false for an invalid next element.
13055  *
13056  Declare integers EndPosition (the position used) and
13057  ReqPosRouteID to hold (when required) the existing route selected, this being set to -1 for not used.
13058  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
13059  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
13060  Check correct type of element - signal/buffers/continuation if ConsecSignalsRoute, else not points, bridge or crossover.
13061  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
13062  EndElement2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2 above).
13063  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
13064  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
13065  linked forward to another route.
13066  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
13067  for same position as start should cover this)
13068  *
13069  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
13070  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
13071  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
13072  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
13073  If the search fails the return false.
13074  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
13075  in the SearchVector to ensure it's entered as part of the new route.
13076  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
13077  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
13078  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed set
13079  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
13080  so return false, with an appropriate message if ConsecSignalsRoute set.
13081 */
13082 
13083 {
13084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
13085  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
13086  int EndPosition; // the position selected
13087 
13088  Track->LCFoundInAutoSigsRoute = false;
13090  TotalSearchCount = 0;
13091  ReqPosRouteID = IDInt(-1); // default value for not used
13092  TTrackElement TrackElement;
13093  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
13094 
13095  // given element as can't select 2-track elements
13096  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
13097  {
13098  Utilities->CallLogPop(214);
13099  return false;
13100  }
13101 
13102  if(Track->IsLCAtHV(19, HLoc, VLoc))
13103  {
13104  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
13105  Utilities->CallLogPop(1908);
13106  return false;
13107  }
13108 
13109 // cancel selection if on original start element
13110  if(EndPosition == StartRoutePosition)
13111  {
13112  Utilities->CallLogPop(215);
13113  return false;
13114  }
13115  if(AutoSigsFlag)
13116  {
13117  if(TrackElement.TrackType == Buffers)
13118  {
13119  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
13120  Utilities->CallLogPop(216);
13121  return false;
13122  }
13123  }
13124  if(ConsecSignalsRoute)
13125  {
13126  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
13127  {
13128  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
13129  Utilities->CallLogPop(217);
13130  return false;
13131  }
13132  }
13133  else // not needed now can't have preferred non-consec signals routes, but leave in
13134  {
13135  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
13136  {
13137  TrainController->StopTTClockMessage(21, "Can't select points, bridge or crossover when building a route");
13138 // makes later adjacent route checks too complicated
13139  Utilities->CallLogPop(218);
13140  return false;
13141  }
13142  }
13143 
13144 // check if train on element
13145  if(TrackElement.TrainIDOnElement > -1)
13146  {
13147  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
13148  Utilities->CallLogPop(219);
13149  return false;
13150  }
13151 
13152 // disallow if not in EveryPrefDir & set EndElement(s)
13153  bool InPrefDirFlag = false;
13154 
13155  bool FoundFlag;
13156  int PrefDirPos0 = -1;
13157  int PrefDirPos1 = -1;
13158  int PrefDirPos2 = -1;
13159  int PrefDirPos3 = -1;
13160 
13161  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
13162  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13163  int PrefDirVecPos[4] =
13164  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13165 
13166  for(int x = 0; x < 4; x++)
13167  {
13168  int b = PrefDirVecPos[x];
13169  if(b > -1)
13170  {
13171  InPrefDirFlag = true;
13172  if(EndElement1.TrackVectorPosition == -1)
13173  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
13174  else
13175  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
13176  }
13177  }
13178  if(!InPrefDirFlag)
13179  {
13181  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
13182  Utilities->CallLogPop(220);
13183  return false;
13184  }
13185 
13186 // check if in an existing route - can't be a bridge so can use a simple 'find'
13187 // bool InRoute = false;
13189  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
13190 
13191  if(RoutePair.first > -1)
13192  {
13193  if(RoutePair.second != 0) // not first element in existing route so no good
13194  {
13195  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
13196  Utilities->CallLogPop(221);
13197  return false;
13198  }
13199  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
13200 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
13201  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
13202  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
13203  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
13204  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
13205  {
13206  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
13207  Utilities->CallLogPop(222);
13208  return false;
13209  }
13210  EndElement1 = RouteElement;
13211  EndElement2 = BlankElement; // only need the route element
13212  EndPosition = EndElement1.TrackVectorPosition;
13213  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
13214  }
13215 
13216 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
13217 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
13218 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
13219 
13220  if(EndElement1.HLoc >= StartElement1.HLoc)
13221  {
13223  SearchLimitHighH = EndElement1.HLoc + 15;
13224  }
13225  else
13226  {
13227  SearchLimitLowH = EndElement1.HLoc - 15;
13229  }
13230 
13231  if(EndElement1.VLoc >= StartElement1.VLoc)
13232  {
13234  SearchLimitHighV = EndElement1.VLoc + 15;
13235  }
13236  else
13237  {
13238  SearchLimitLowV = EndElement1.VLoc - 15;
13240  }
13241 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
13242  check & TotalSearchCounts check
13243  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
13244  {
13245  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
13246  Utilities->CallLogPop(1693);
13247  return false;
13248  }
13249 */
13250 // check if adjacent to start and disallow
13251  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13252  {
13254  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
13255 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
13256 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
13257  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
13258  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
13259  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
13260  {
13261  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
13262  Utilities->CallLogPop(223);
13263  return false;
13264  }
13265 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
13266 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
13267  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
13268  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
13269  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
13270  {
13271  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
13272  Utilities->CallLogPop(224);
13273  return false;
13274  }
13275 
13276 // check if adjacent to end of a route & disallow
13278  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
13279  {
13280  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
13281  Utilities->CallLogPop(225);
13282  return false;
13283  }
13284  }
13285 
13286 // check for same route as start element
13288  {
13289  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
13290  Utilities->CallLogPop(226);
13291  return false;
13292  }
13293 
13294 // check for a looping route
13295  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
13296  {
13298  {
13299  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
13300  Utilities->CallLogPop(1844);
13301  return false;
13302  }
13303  }
13304 
13305 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
13306 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
13307 // and don't want to add it again
13308  if(StartSelectionRouteID > -1)
13309  {
13310  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13311  AutoSigsFlag))
13312  {
13313  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
13314  if(PointsToBeChanged(5))
13315  {
13316  PointsChanged = true;
13317  }
13318  Utilities->CallLogPop(227);
13319  return true;
13320  }
13321  else if(ConsecSignalsRoute && !Track->LCFoundInAutoSigsRouteMessageGiven)
13323  Utilities->CallLogPop(228);
13324  return false;
13325  }
13326  else
13327  {
13328 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
13329 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
13330 
13331 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
13332 // note that a blank element will have XLinkPos set to -1
13333  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
13334  {
13335  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13336  AutoSigsFlag))
13337  {
13338  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
13339  if(PointsToBeChanged(6))
13340  {
13341  PointsChanged = true;
13342  }
13343  Utilities->CallLogPop(229);
13344  return true;
13345  }
13346  else
13347  {
13350  Utilities->CallLogPop(230);
13351  return false;
13352  }
13353  }
13354  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
13355  {
13356  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13357  AutoSigsFlag))
13358  {
13359  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
13360  if(PointsToBeChanged(7))
13361  {
13362  PointsChanged = true;
13363  }
13364  Utilities->CallLogPop(231);
13365  return true;
13366  }
13367  else
13368  {
13371  Utilities->CallLogPop(232);
13372  return false;
13373  }
13374  }
13375 
13376  // now start off in the best direction
13377  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
13378  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
13379  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
13380  // unless new problems are found.
13381  if(StartElement1.XLinkPos == BestPos)
13382  {
13383  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13384  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13385  AutoSigsFlag))
13386  {
13387  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
13388  if(PointsToBeChanged(8))
13389  {
13390  PointsChanged = true;
13391  }
13392  Utilities->CallLogPop(233);
13393  return true;
13394  }
13395  else if(StartElement2.TrackVectorPosition > -1)
13396  {
13397  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13398  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13399  AutoSigsFlag))
13400  {
13401  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
13402  if(PointsToBeChanged(9))
13403  {
13404  PointsChanged = true;
13405  }
13406  Utilities->CallLogPop(234);
13407  return true;
13408  }
13409  }
13410  }
13411  else if(StartElement2.TrackVectorPosition > -1)
13412  {
13413  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13414  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13415  AutoSigsFlag))
13416  {
13417  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
13418  if(PointsToBeChanged(10));
13419  {
13420  PointsChanged = true;
13421  }
13422  Utilities->CallLogPop(1857);
13423  return true;
13424  }
13425  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13426  AutoSigsFlag))
13427  {
13428  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
13429  if(PointsToBeChanged(11));
13430  {
13431  PointsChanged = true;
13432  }
13433  Utilities->CallLogPop(1858);
13434  return true;
13435  }
13436  }
13437  else if(StartElement1.XLinkPos == (1 - BestPos))
13438  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction
13439  {
13440  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
13441  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13442  AutoSigsFlag))
13443  {
13444  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
13445  if(PointsToBeChanged(12))
13446  {
13447  PointsChanged = true;
13448  }
13449  Utilities->CallLogPop(1864);
13450  return true;
13451  }
13452  }
13453  }
13456  Utilities->CallLogPop(235);
13457  return false;
13458 }
13459 
13460 // ---------------------------------------------------------------------------
13461 
13462 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
13463 {
13464  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
13465  if(PrefDirSize() == 0)
13466  {
13467  Utilities->CallLogPop(1704);
13468  return;
13469  }
13470  for(unsigned int x = 0; x < PrefDirSize(); x++)
13471  {
13472  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13473  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13474  {
13475  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13476  TempPrefDirElement.EXGraphicPtr);
13477  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
13478  {
13479  if(x == 0)
13480  {
13481  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13482  TempPrefDirElement.EntryDirectionGraphicPtr);
13483  }
13484  if(x == (PrefDirSize() - 1))
13485  {
13486  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
13487  TempPrefDirElement.EntryDirectionGraphicPtr);
13488  }
13489  }
13490  }
13491  }
13492 
13493  Utilities->CallLogPop(1705);
13494 }
13495 
13496 // ---------------------------------------------------------------------------
13497 
13498 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
13499  TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, int EndPosition, bool AutoSigsFlag)
13500 
13501 /*
13502  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
13503  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If
13504  it's an element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
13505  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
13506  Return false if any element (apart from RequiredPosition) is on an existing route.
13507  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point).
13508 
13509  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
13510  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
13511  added during the function so as to leave it exactly as it was on entering, then return false).
13512  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
13513  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
13514  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
13515  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
13516  the route number that the searched-for element is the start of if any, and set to -1 if no
13517  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
13518  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
13519  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
13520  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
13521 
13522  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
13523  or a continuation, and fail if so. Check if reached a valid signal in ConsecSignalsRoute on any but firstpass
13524  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
13525  for recursive calls), and fail if so as user should always select the next signal in a route.
13526  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
13527  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
13528  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
13529  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
13530  or if train on element (unless a bridge & train on different track).
13531  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
13532  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
13533  a leading point where both trailing directions are in EveryPrefDir, if not fail.
13534  Check if found RequiredPosition & that it's a signal/buffer/continuation if ConsecSignalsRoute set. If OK save in SearchVector with
13535  AutoSignals member set if AutoSigsFlag set, then return true.
13536  Check & fail if a buffer or continuation (if element = RequiredPosition will have succeeded in the above check.
13537 
13538  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
13539  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
13540  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
13541  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
13542  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
13543  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
13544  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
13545 
13546  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
13547  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
13548 */
13549 
13550 {
13551  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
13552  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
13553  AnsiString((short)AutoSigsFlag));
13554  int VectorCount = 0;
13555  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
13556 
13557 // check for a fouled diagonal for first element. Added for v1.3.2
13558  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
13559  {
13560  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
13561  {
13562  for(int x = 0; x < VectorCount; x++)
13563  SearchVector.erase(SearchVector.end() - 1);
13564  Utilities->CallLogPop(2043);
13565  return false;
13566  }
13567  }
13568 
13569  bool FirstPass = true;
13570 
13571  while(true)
13572  {
13573  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
13574  {
13575  Track->LCFoundInAutoSigsRoute = true;
13576  }
13577  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
13578  {
13579  for(int x = 0; x < VectorCount; x++)
13580  SearchVector.erase(SearchVector.end() - 1);
13581  Utilities->CallLogPop(1926);
13582  return false;
13583  }
13584  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
13585  {
13586  for(int x = 0; x < VectorCount; x++)
13587  SearchVector.erase(SearchVector.end() - 1);
13588  Utilities->CallLogPop(236);
13589  return false;
13590  }
13591  if(!FirstPass && (ConsecSignalsRoute) && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
13592  // reached a valid signal that isn't the required position, user should always select the next
13593  // signal in a route so have to fail
13594  // won't affect recurive searches as for them the first pass element is always a point
13595  {
13596  for(int x = 0; x < VectorCount; x++)
13597  SearchVector.erase(SearchVector.end() - 1);
13598  Utilities->CallLogPop(237);
13599  return false;
13600  }
13601  FirstPass = false;
13602  int NextPosition = PrefDirElement.Conn[XLinkPos];
13603  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
13604  TPrefDirElement SearchElement(NextTrackElement);
13605  SearchElement.TrackVectorPosition = NextPosition;
13606  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
13607  SearchElement.ELinkPos = NextELinkPos;
13608  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
13609  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
13610  int NextXLinkPos;
13611  if(SearchElement.ELinkPos == 0)
13612  NextXLinkPos = 1;
13613  if(SearchElement.ELinkPos == 1)
13614  NextXLinkPos = 0;
13615  if(SearchElement.ELinkPos == 2)
13616  NextXLinkPos = 3;
13617  if(SearchElement.ELinkPos == 3)
13618  NextXLinkPos = 2;
13619  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
13620  {
13621  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
13622 // note that may be buffers, continuation or gap
13623  SearchElement.XLinkPos = NextXLinkPos;
13624  }
13625 // can't set XLink or XLinkPos yet if the element is a leading point.
13626 
13627 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
13628  for(unsigned int x = 0; x < SearchVector.size(); x++)
13629  {
13630  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
13631  {
13632  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
13633  // OK if a bridge & routes on different tracks
13634  {
13635  for(int x = 0; x < VectorCount; x++)
13636  SearchVector.erase(SearchVector.end() - 1);
13637  Utilities->CallLogPop(238);
13638  return false;
13639  }
13640  }
13641  }
13642 
13643 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
13644  TAllRoutes::TRouteElementPair SecondPair;
13646  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
13647  if(RoutePair.first > -1)
13648  {
13649  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13650  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
13651  RoutePair.second).ELinkPos)))
13652  {
13653  // still OK if start of an expected route
13654  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
13655  {
13656  for(int x = 0; x < VectorCount; x++)
13657  SearchVector.erase(SearchVector.end() - 1);
13658  Utilities->CallLogPop(239);
13659  return false; // only allow for start of an expected route
13660  }
13661  }
13662  }
13663  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
13664  {
13665  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
13666  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
13667  SecondPair.second).ELinkPos)))
13668  {
13669  // still OK if start of an expected route
13670  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
13671  {
13672  for(int x = 0; x < VectorCount; x++)
13673  SearchVector.erase(SearchVector.end() - 1);
13674  Utilities->CallLogPop(240);
13675  return false; // only allow for start of an expected route
13676  }
13677  }
13678  }
13679 
13680 // check if a train on element, unless a bridge & train on different track
13681 // OK of same train as start element - no drop this
13682 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
13683  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
13684  {
13685  for(int x = 0; x < VectorCount; x++)
13686  SearchVector.erase(SearchVector.end() - 1);
13687  Utilities->CallLogPop(241);
13688  return false;
13689  }
13690  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
13691  {
13692  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
13693  {
13694  for(int x = 0; x < VectorCount; x++)
13695  SearchVector.erase(SearchVector.end() - 1);
13696  Utilities->CallLogPop(242);
13697  return false;
13698  }
13699  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
13700  {
13701  for(int x = 0; x < VectorCount; x++)
13702  SearchVector.erase(SearchVector.end() - 1);
13703  Utilities->CallLogPop(243);
13704  return false;
13705  }
13706  }
13707 
13708 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
13709  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13710  {
13711  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13712  {
13713  for(int x = 0; x < VectorCount; x++)
13714  SearchVector.erase(SearchVector.end() - 1);
13715  Utilities->CallLogPop(244);
13716  return false;
13717  }
13718  }
13719 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
13720 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
13721  bool InPrefDirFlag = false;
13722  PrefDirElement1 = BlankElement;
13723  PrefDirElement2 = BlankElement;
13724 
13725  bool FoundFlag;
13726  int PrefDirPos0 = -1;
13727  int PrefDirPos1 = -1;
13728  int PrefDirPos2 = -1;
13729  int PrefDirPos3 = -1;
13731  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13732  int PrefDirVecPos[4] =
13733  {PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3};
13734  for(int x = 0; x < 4; x++)
13735  {
13736  int b = PrefDirVecPos[x];
13737  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
13738  {
13739  InPrefDirFlag = true;
13740  if(PrefDirElement1.TrackVectorPosition == -1)
13741  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
13742  else
13743  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
13744  }
13745  }
13746  if(!InPrefDirFlag)
13747  {
13748  for(int x = 0; x < VectorCount; x++)
13749  SearchVector.erase(SearchVector.end() - 1);
13750  Utilities->CallLogPop(245);
13751  return false;
13752  }
13753 
13754 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
13755 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
13756 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
13758  {
13759  for(int x = 0; x < VectorCount; x++)
13760  SearchVector.erase(SearchVector.end() - 1);
13761  Utilities->CallLogPop(1690);
13762  return false;
13763  }
13764 
13765 // check if found it
13766  if(SearchElement.TrackVectorPosition == RequiredPosition)
13767  {
13768 // need to ensure a signal/buffer/continuation if ConsecSignalsRoute set,
13769  if(ConsecSignalsRoute && (SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
13770  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
13771  {
13772  for(int x = 0; x < VectorCount; x++)
13773  SearchVector.erase(SearchVector.end() - 1);
13774  Utilities->CallLogPop(246);
13775  return false;
13776  } // if(ConsecSignalsRoute && (SearchElement.Config[SearchElement.XLinkPos] != Signal).......
13777  if(AutoSigsFlag)
13778  {
13779  PrefDirElement1.AutoSignals = true;
13780  }
13781  if(ConsecSignalsRoute)
13782  {
13783  PrefDirElement1.ConsecSignals = true;
13784  }
13786  {
13788  {
13789  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
13791  }
13792  for(int x = 0; x < VectorCount; x++)
13793  SearchVector.erase(SearchVector.end() - 1);
13794  Utilities->CallLogPop(1928);
13795  return false;
13796  }
13797  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
13798  VectorCount++; // not really needed but include for tidyness
13799  TotalSearchCount++;
13800  Utilities->CallLogPop(247);
13801  return true;
13802  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
13803 // check if a buffer or continuation (end of search on this leg if not found by now)
13804  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
13805  {
13806  for(int x = 0; x < VectorCount; x++)
13807  SearchVector.erase(SearchVector.end() - 1);
13808  Utilities->CallLogPop(248);
13809  return false;
13810  }
13811 // check if SearchVector exceeds a size of 150
13812  if(SearchVector.size() > 150)
13813  {
13814  for(int x = 0; x < VectorCount; x++)
13815  SearchVector.erase(SearchVector.end() - 1);
13816  Utilities->CallLogPop(1420);
13817  return false;
13818  }
13819 // check if reached a leading point
13820  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
13821  {
13822 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
13823  int SearchPos1 = SearchElement.Attribute + 1;
13824  int SearchPos2;
13825  if(SearchPos1 == 2)
13826  SearchPos1++;
13827  if(SearchPos1 == 1)
13828  SearchPos2 = 3;
13829  else
13830  SearchPos2 = 1;
13831  SearchElement.XLink = SearchElement.Link[SearchPos1];
13832  SearchElement.XLinkPos = SearchPos1;
13833  InPrefDirFlag = false;
13834  if(SearchElement.XLink == PrefDirElement1.XLink)
13835  {
13836  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
13837  InPrefDirFlag = true;
13838  }
13839  else if(SearchElement.XLink == PrefDirElement2.XLink)
13840  {
13841  SearchElement = PrefDirElement2;
13842  InPrefDirFlag = true;
13843  }
13844 // push element with XLink set to position [SearchPos1] if on a PrefDir
13845  if(InPrefDirFlag)
13846  {
13847 // check for a fouled diagonal for leading point for XLinkPos == 1)
13848  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13849  {
13850  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13851  {
13852  for(int x = 0; x < VectorCount; x++)
13853  SearchVector.erase(SearchVector.end() - 1);
13854  Utilities->CallLogPop(249);
13855  return false;
13856  }
13857  }
13858  if(AutoSigsFlag)
13859  {
13860  SearchElement.AutoSignals = true;
13861  }
13862  if(ConsecSignalsRoute)
13863  {
13864  SearchElement.ConsecSignals = true;
13865  }
13866  SearchVector.push_back(SearchElement);
13867  VectorCount++;
13868  TotalSearchCount++;
13869 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
13870  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13871  AutoSigsFlag))
13872  {
13874  {
13876  {
13877  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
13879  }
13880  for(int x = 0; x < VectorCount; x++)
13881  SearchVector.erase(SearchVector.end() - 1);
13882  Utilities->CallLogPop(1929);
13883  return false;
13884  }
13885  Utilities->CallLogPop(250);
13886  return true;
13887  }
13888  else
13889  {
13890 // remove leading point with XLinkPos [1]
13891  SearchVector.erase(SearchVector.end() - 1);
13892  VectorCount--;
13893  }
13894  }
13895 // XLink set to position [SearchPos2]
13896  SearchElement.XLink = SearchElement.Link[SearchPos2];
13897  SearchElement.XLinkPos = SearchPos2;
13898  if(SearchElement.XLink == PrefDirElement1.XLink)
13899  {
13900  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
13901  }
13902  else if(SearchElement.XLink == PrefDirElement2.XLink)
13903  {
13904  SearchElement = PrefDirElement2;
13905  }
13906  else // failed to find a valid exit from the point
13907  {
13908  for(int x = 0; x < VectorCount; x++)
13909  SearchVector.erase(SearchVector.end() - 1);
13910  Utilities->CallLogPop(251);
13911  return false;
13912  }
13913 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
13914  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
13915  {
13916  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
13917  {
13918  for(int x = 0; x < VectorCount; x++)
13919  SearchVector.erase(SearchVector.end() - 1);
13920  Utilities->CallLogPop(252);
13921  return false;
13922  }
13923  }
13924 // push element with XLink set to position [SearchPos2]
13925  if(AutoSigsFlag)
13926  {
13927  SearchElement.AutoSignals = true;
13928  }
13929  if(ConsecSignalsRoute)
13930  {
13931  SearchElement.ConsecSignals = true;
13932  }
13933  SearchVector.push_back(SearchElement);
13934  VectorCount++;
13935  TotalSearchCount++;
13936 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
13937  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignalsRoute, EndPosition,
13938  AutoSigsFlag))
13939  {
13941  {
13943  {
13944  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
13946  }
13947  for(int x = 0; x < VectorCount; x++)
13948  SearchVector.erase(SearchVector.end() - 1);
13949  Utilities->CallLogPop(1930);
13950  return false;
13951  }
13952  Utilities->CallLogPop(1592);
13953  return true;
13954  }
13955  else
13956  {
13957  for(int x = 0; x < VectorCount; x++)
13958  SearchVector.erase(SearchVector.end() - 1);
13959  Utilities->CallLogPop(253);
13960  return false;
13961  }
13962  } // if leading point
13963 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
13964  SearchElement = PrefDirElement1;
13965  if(AutoSigsFlag)
13966  {
13967  SearchElement.AutoSignals = true;
13968  }
13969  if(ConsecSignalsRoute)
13970  {
13971  SearchElement.ConsecSignals = true;
13972  }
13973  SearchVector.push_back(SearchElement);
13974  VectorCount++;
13975  TotalSearchCount++;
13976  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
13977  PrefDirElement = SearchElement;
13978  } // while(true)
13979 }
13980 
13981 // ---------------------------------------------------------------------------
13982 
13983 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
13984 {
13985 /*
13986  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
13987  and the new or extended route created from that. Hence action varies depending on whether
13988  it is a completely new route, or an extension of an existing route at the beginning or the end.
13989  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
13990  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
13991 
13992  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
13993  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
13994  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
13995  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
13996  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
13997  is decremented;
13998  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
13999  from the existing route, then enter the new route into the AllRoutesVector;
14000  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
14001  then enter the new route into the AllRoutesVector.
14002 
14003  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
14004  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
14005  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
14006  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
14007  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
14008  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
14009  for the new route and return;
14010  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
14011  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
14012 
14013  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
14014  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
14015  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
14016 */
14017  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
14018  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
14019  if(SearchVector.size() < 1)
14020  {
14021  Utilities->CallLogPop(254);
14022  return;
14023  }
14025  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
14026  {
14027  Utilities->CallLogPop(255);
14028  return;
14029  }
14030 
14031  TAllRoutes::TLockedRouteClass LockedRouteObject;
14032 
14034  unsigned int TruncatePrefDirPosition = 0;
14035 
14036  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
14037 /* if have ReqPosRouteID:
14038  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
14039  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
14040  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
14041  the existing route, then enter the new route into the AllRoutesVector
14042  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
14043  then enter the new route into the AllRoutesVector
14044 */
14045  {
14048  {
14049  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
14050  x++) // start at 1 as first element already in SearchVector
14051  {
14053  }
14054  // note that route numbers in map adjusted when ReqPos route cleared
14056  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
14057  // set during ClearRouteDuringRouteBuildingAt
14059  {
14062  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
14063  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
14064  }
14065  }
14067  {
14069  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
14070  }
14072  {
14073  SearchVector.pop_back();
14074  }
14075  }
14076 
14077  if(StartSelectionRouteID > -1)
14078 /* if have StartSelectionRouteID:
14079  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
14080  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
14081  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
14082  then add it to the start of the new route, then enter the new route into the AllRoutesVector
14083  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
14084 */
14085  {
14087  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
14088  {
14091  {
14092  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
14093  for(unsigned int x = 0; x < SearchVector.size(); x++)
14094  {
14096  RouteNumber, GetFixedSearchElementAt(3, x));
14097  // find & store locked route truncate position in PrefDirVector for later use
14099  {
14100  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
14101  {
14102  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
14103  }
14104  }
14105  }
14107  {
14108  throw Exception("Error - failed to validate extended route for preferred route");
14109  }
14112  if(!AutoSigsFlag)
14113  {
14114  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
14115  }
14116  // now add the reinstated locked route if required and set signals accordingly
14118  {
14119  LockedRouteObject.RouteNumber = RouteNumber;
14120  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
14121  // now reset the signals for the locked route
14122  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
14123  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
14124  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
14125  // return all signals to red in route section to be truncated
14126  {
14127  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
14128  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
14129  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
14130  {
14131  TrackElement.Attribute = 0;
14132  Track->PlotSignal(10, TrackElement, Display);
14133  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
14134  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
14135  }
14136  }
14137  }
14138  AllRoutes->CheckMapAndRoutes(1); // test
14139  Utilities->CallLogPop(256);
14140  return;
14141  }
14143  {
14146  RouteElement.AutoSignals = true;
14147  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true); // true for ConsecSignalsRoute
14148  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // true for ConsecSignalsRoute
14149  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
14150  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
14151  }
14152  }
14153  else
14154  {
14156  }
14157 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
14158 // AllRoutesVector hence nothing to do here
14159  }
14160 
14161  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
14162  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
14163  {
14164  throw Exception("Error - failed to validate single route for preferred route");
14165  }
14166  AllRoutes->StoreOneRoute(1, this);
14167  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
14168  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
14169  if(!AutoSigsFlag)
14170  {
14171  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
14172  }
14173  AllRoutes->CheckMapAndRoutes(2); // test
14174  Utilities->CallLogPop(257);
14175 }
14176 
14177 // ---------------------------------------------------------------------------
14178 
14179 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon) // Return true if OK.
14180 {
14181 /*
14182  [Note: original intention was to allow both consecutive signals and non-consecutive signals for routes
14183  on track with or without pref dirs set, hence the bool ConsecSignalsRoute, subsequently decided to
14184  make all unrestricted routes nonconsecutive signals, so that parameter will always be false. leave
14185  as is in case wish to change at a later time]
14186 
14187  If Callon true then called to set an unrestricted call-on route - suppress messages
14188  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
14189  & ensure signal/buffers/continuation.
14190  Note that can't select ConsecSignalsRoute for non-preferred routes.
14191  Check if train on element & disallow.
14192  Set default values for retained parameters:-
14193  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
14194  StartSelectionRouteID = route that selection starts in if there is one;
14195 
14196  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
14197  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
14198  validity. This is just for safety reasons, the PrefDir values aren't used.
14199  StartElement1 & 2 are set to these PrefDirelements.
14200 
14201  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
14202 
14203  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
14204  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
14205  blank StartElement2 (only want to use the route element), then return true.
14206  Check if adjacent to start or end of an existing route & disallow if so.
14207  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
14208  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
14209  SetRemainingSearchVectorValues().
14210  Finally add the required element to the SearchVector & return true.
14211 */
14212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14213  AnsiString(VLoc) + "," + AnsiString((short)Callon));
14214  ClearRoute();
14215  int TrackVectorPosition;
14216  TTrackElement TrackElement;
14217  TPrefDirElement FirstElement, LastElement;
14218 
14219  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14220  {
14221  Utilities->CallLogPop(258);
14222  return false;
14223  }
14224  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
14225  {
14226  if(!Callon)
14227  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
14228 // makes later adjacent route checks too complicated
14229  Utilities->CallLogPop(259);
14230  return false;
14231  }
14232 
14233  if(Track->IsLCAtHV(21, HLoc, VLoc))
14234  {
14235  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
14236  Utilities->CallLogPop(1910);
14237  return false;
14238  }
14239 
14240 // check if selected a train & disallow if so
14241  if(TrackElement.TrainIDOnElement > -1)
14242  {
14243  if(!Callon)
14244  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
14245  Utilities->CallLogPop(260);
14246  return false;
14247  }
14248 
14249 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14250  TPrefDirElement PrefDirElement;
14251  int LockedVectorNumber;
14252 
14253  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14254  {
14255  if(!Callon)
14256  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
14257  Utilities->CallLogPop(261);
14258  return false;
14259  }
14260  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14261  {
14262  if(!Callon)
14263  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
14264  Utilities->CallLogPop(262);
14265  return false;
14266  }
14267 
14269 // AdjacentStartRouteNumber = -1;
14270  StartRoutePosition = TrackVectorPosition;
14271 // StartRouteSelectPosition = TrackVectorPosition;
14272 
14273  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
14274  TPrefDirElement PrefDirElement2(TrackElement);
14275 
14276  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
14277  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
14278  TPrefDirElement BlankElement;
14279 
14280  PrefDirElement1.ELinkPos = 0;
14281  PrefDirElement1.XLinkPos = 1;
14282  PrefDirElement1.ELink = PrefDirElement1.Link[0];
14283  PrefDirElement1.XLink = PrefDirElement1.Link[1];
14284  if(!(PrefDirElement1.EntryExitNumber()))
14285  {
14286  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
14287  // no need for bridge check as bridge selections not allowed
14288  }
14289  PrefDirElement1.CheckCount = 9;
14290  PrefDirElement2.ELinkPos = 1;
14291  PrefDirElement2.XLinkPos = 0;
14292  PrefDirElement2.ELink = PrefDirElement2.Link[1];
14293  PrefDirElement2.XLink = PrefDirElement2.Link[0];
14294  if(!(PrefDirElement2.EntryExitNumber()))
14295  {
14296  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
14297  }
14298  PrefDirElement2.CheckCount = 9; // both now set
14299 
14300 // set StartElements to the above PrefDirElements
14301  StartElement1 = PrefDirElement1;
14302  StartElement2 = PrefDirElement2;
14303 
14304 // no PrefDir check needed as doesn't need to be in a PrefDir
14305 
14306 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
14308  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14309 
14310  if(RoutePair.first > -1)
14311  {
14312  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14313  {
14314  if(!Callon)
14315  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
14316  Utilities->CallLogPop(263);
14317  return false;
14318  }
14319  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
14320  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14321  {
14322  if(!Callon)
14323  TrainController->StopTTClockMessage(39, "No forward connection from this position");
14324  Utilities->CallLogPop(264);
14325  return false;
14326  }
14327  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
14328  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14329  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14330  {
14331  if(!Callon)
14332  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
14333  Utilities->CallLogPop(265);
14334  return false;
14335  }
14336  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
14338  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
14339  StartElement2 = BlankElement; // only use the route element
14341  Utilities->CallLogPop(266);
14342  return true; // all retained values set
14343  }
14344 
14345  else // selection not in an existing route
14346  {
14347 // check if it's adjacent to start of an an existing route,
14348  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14349  {
14350  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
14351  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14352  {
14353  if(!Callon)
14354  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
14355  Utilities->CallLogPop(267);
14356  return false;
14357  }
14358  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14359  {
14360  if(!Callon)
14361  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
14362  Utilities->CallLogPop(268);
14363  return false;
14364  }
14365  }
14366 // check if it's adjacent to end of an an existing route,
14367  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14368  {
14370  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14371  {
14372  if(!Callon)
14373  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
14374  Utilities->CallLogPop(269);
14375  return false;
14376  }
14377  }
14378  // not in a route or adjacent to start or end of a route
14379  // in this case reset all variable values to -1 & CheckCount to 4
14380  StartElement1.ELink = -1;
14381  StartElement1.ELinkPos = -1;
14382  StartElement1.XLink = -1;
14383  StartElement1.XLinkPos = -1;
14384  StartElement1.EXNumber = -1;
14386  StartElement2 = BlankElement;
14387  SearchVector.push_back(StartElement1);
14388  Utilities->CallLogPop(270);
14389  return true;
14390  }
14391 }
14392 
14393 // ---------------------------------------------------------------------------
14394 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
14395 
14396 /*
14397  If Callon true then called to set an unrestricted call-on route - suppress messages & allow points to be selected
14398 
14399  Declare the following integers:-
14400  EndPosition - TrackVectorPosition for the selection;
14401  ReqPosRouteID - for the existing route selected, set to -1 if not used and initially;
14402  Check if selection is a valid track element and set EndPosition.
14403  Cancel if select original start element, then check that not points, bridge or crossover.
14404  Check & fail if a train is present at the selection.
14405  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
14406  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
14407  No check needed for selection in EveryPrefDir.
14408  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
14409  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
14410  as don't need it if in a route.
14411  Check if selection adj to start or end of a route and disallow.
14412  Fail if select same route as starting route, though should already have failed earlier if this is so.
14413 
14414  If there's a StartSelectionRouteID then StartElement1 will be set to
14415  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
14416  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
14417  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
14418  to add the new route to the AllRoutesVectorPtr.
14419  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
14420  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
14421  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
14422  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
14423  the search vector values and return.
14424  If not returned yet then have failed to find the required element so return false with no message.
14425 */
14426 
14427 {
14428 // get EndPosition
14429  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
14430  AnsiString(VLoc));
14431  int EndPosition;
14432 
14433  TotalSearchCount = 0;
14434  ReqPosRouteID = IDInt(-1); // for not used
14435  TTrackElement TrackElement;
14436  TPrefDirElement BlankElement;
14437 
14438  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14439  {
14440  Utilities->CallLogPop(271);
14441  return false;
14442  }
14443 // EndPosition = EndSelectPosition;
14444 // cancel selection if on original start element
14445  if(EndPosition == StartRoutePosition)
14446  {
14447  Utilities->CallLogPop(272);
14448  return false;
14449  }
14450 
14451  if(Track->IsLCAtHV(22, HLoc, VLoc))
14452  {
14453  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
14454  Utilities->CallLogPop(1911);
14455  return false;
14456  }
14457 
14458  if((TrackElement.TrackType == Points) && !Callon)
14459  {
14460  if(!Callon)
14461  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
14462 // makes later adjacent route checks too complicated
14463  Utilities->CallLogPop(273);
14464  return false;
14465  }
14466 
14467  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
14468  {
14469  if(!Callon)
14470  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
14471 // makes later adjacent route checks too complicated
14472  Utilities->CallLogPop(1861);
14473  return false;
14474  }
14475 
14476 // check if train on element
14477  if(TrackElement.TrainIDOnElement > -1)
14478  {
14479  if(!Callon)
14480  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
14481  Utilities->CallLogPop(274);
14482  return false;
14483  }
14484 
14485 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
14486 // check passed)
14487  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
14488  TPrefDirElement EndElement2(TrackElement);
14489 
14490  EndElement1.TrackVectorPosition = EndPosition;
14491  EndElement2.TrackVectorPosition = EndPosition;
14492  EndElement1.ELinkPos = 0;
14493  EndElement1.XLinkPos = 1;
14494  EndElement1.ELink = EndElement1.Link[0];
14495  EndElement1.XLink = EndElement1.Link[1];
14496  if(!(EndElement1.EntryExitNumber()))
14497  {
14498  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
14499  }
14500  EndElement1.CheckCount = 9;
14501  EndElement2.ELinkPos = 1;
14502  EndElement2.XLinkPos = 0;
14503  EndElement2.ELink = EndElement2.Link[1];
14504  EndElement2.XLink = EndElement2.Link[0];
14505  if(!(EndElement2.EntryExitNumber()))
14506  {
14507  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
14508  }
14509  EndElement2.CheckCount = 9; // both now set
14510 
14511 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14512 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14513 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14514 
14515  if(EndElement1.HLoc >= StartElement1.HLoc)
14516  {
14518  SearchLimitHighH = EndElement1.HLoc + 15;
14519  }
14520  else
14521  {
14522  SearchLimitLowH = EndElement1.HLoc - 15;
14524  }
14525 
14526  if(EndElement1.VLoc >= StartElement1.VLoc)
14527  {
14529  SearchLimitHighV = EndElement1.VLoc + 15;
14530  }
14531  else
14532  {
14533  SearchLimitLowV = EndElement1.VLoc - 15;
14535  }
14536 
14537 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14538  check & TotalSearchCounts check
14539  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14540  {
14541  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
14542  Utilities->CallLogPop(1694);
14543  return false;
14544  }
14545 */
14546 // don't need EveryPrefDir check for NonPreferredRoute
14547 
14548 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
14549 // bool InRoute = false;
14551  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14552 
14553  if(RoutePair.first > -1)
14554  {
14555  if(RoutePair.second != 0) // not first element in existing route so no good
14556  {
14557  if(!Callon)
14558  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
14559  Utilities->CallLogPop(275);
14560  return false;
14561  }
14562  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
14563 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14564  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
14565  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14566  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14567  {
14568  if(!Callon)
14569  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
14570  Utilities->CallLogPop(276);
14571  return false;
14572  }
14573  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
14574  EndElement2 = BlankElement; // only need the route element
14575  EndPosition = EndElement1.TrackVectorPosition;
14576  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
14577  }
14578 
14579 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
14580  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14581  {
14582  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
14583  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
14584 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14585 // && (AdjPosition != StartRoutePosition))
14586  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14587  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14588  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
14589  {
14590  if(!Callon)
14591  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
14592  Utilities->CallLogPop(277);
14593  return false;
14594  }
14595 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14596 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
14597  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14598  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14599  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
14600  (AdjPosition != StartRoutePosition))
14601  {
14602  if(!Callon)
14603  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
14604  Utilities->CallLogPop(278);
14605  return false;
14606  }
14607 
14608 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
14610  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
14611  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
14612  {
14613  if(!Callon)
14614  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
14615  Utilities->CallLogPop(279);
14616  return false;
14617  }
14618  }
14619 
14620 // check for same route as start element
14622  {
14623  if(!Callon)
14624  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
14625  Utilities->CallLogPop(280);
14626  return false;
14627  }
14628 
14629 // check for a looping route
14630  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14631  {
14633  {
14634  if(!Callon)
14635  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
14636  Utilities->CallLogPop(1845);
14637  return false;
14638  }
14639  }
14640 
14641 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14642 // so search from this element.
14643 
14644  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
14645 
14646  if(StartSelectionRouteID > -1)
14647  {
14648  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
14649  {
14651  if(PointsToBeChanged(0))
14652  {
14653  PointsChanged = true;
14654  }
14655  Utilities->CallLogPop(281);
14656  return true;
14657  }
14658  else
14659  {
14660  if(!Callon)
14662  Utilities->CallLogPop(282);
14663  return false;
14664  }
14665  }
14666  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
14667  // search on the 2 ways out of the element, which has to be a 2-ended element
14668  {
14669 // check if selection adjacent to start element and if so use that
14670  if(SearchVector.at(0).Conn[0] == EndPosition)
14671  {
14672  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
14673  {
14675  if(PointsToBeChanged(1))
14676  {
14677  PointsChanged = true;
14678  }
14679  Utilities->CallLogPop(283);
14680  return true;
14681  }
14682  else
14683  {
14684  if(!Callon)
14686  Utilities->CallLogPop(284);
14687  return false;
14688  }
14689  }
14690  else if(SearchVector.at(0).Conn[1] == EndPosition)
14691  {
14692  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
14693  {
14695  if(PointsToBeChanged(2))
14696  {
14697  PointsChanged = true;
14698  }
14699  Utilities->CallLogPop(285);
14700  return true;
14701  }
14702  else
14703  {
14704  if(!Callon)
14706  Utilities->CallLogPop(286);
14707  return false;
14708  }
14709  }
14710  // now start off in the best direction
14711  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
14712 
14713  if(SearchVector.at(0).Config[BestPos] != End)
14714  {
14715  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14716  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
14717  {
14719  if(PointsToBeChanged(3))
14720  {
14721  PointsChanged = true;
14722  }
14723  Utilities->CallLogPop(287);
14724  return true;
14725  }
14726  }
14727  if(SearchVector.at(0).Config[1 - BestPos] != End)
14728  {
14729  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14730  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
14731  {
14733  if(PointsToBeChanged(4))
14734  {
14735  PointsChanged = true;
14736  }
14737  Utilities->CallLogPop(288);
14738  return true;
14739  }
14740  }
14741  }
14742  if(!Callon)
14744  Utilities->CallLogPop(289);
14745  return false;
14746 }
14747 
14748 // ---------------------------------------------------------------------------
14749 
14750 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
14751 /*
14752  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
14753  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
14754  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
14755  Keep a count of entries in SearchVector during the current function call, so that this number can be
14756  erased for an unproductive branch search.
14757  First check (within the loop) whether XLink leads to an End & return false if so.
14758  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
14759  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14760  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
14761  train on element (unless a bridge & train on different track), or if element
14762  fouls an existing diagonal route (except if element is a leading point - these checked later).
14763  Then check if found required element. If so save it & return true.
14764  If not the required element check if buffer or continuation, & if so erase all searchvector
14765  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
14766  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
14767  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
14768  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
14769  When return true have 8 items from CheckCount established, only waiting for EXNumber
14770 */
14771 {
14772  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
14773  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
14774  int VectorCount = 0;
14775 
14776 // check for a fouled diagonal for first element. Added for v1.3.2
14777  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
14778  (CurrentTrackElement.Link[XLinkPos] == 9))
14779  {
14780  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
14781  {
14782  for(int x = 0; x < VectorCount; x++)
14783  SearchVector.erase(SearchVector.end() - 1);
14784  Utilities->CallLogPop(2044);
14785  return false;
14786  }
14787  }
14788 
14789  while(true)
14790  {
14791  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
14792  {
14793  for(int x = 0; x < VectorCount; x++)
14794  SearchVector.erase(SearchVector.end() - 1);
14795  Utilities->CallLogPop(1927);
14796  return false;
14797  }
14798  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
14799  {
14800  for(int x = 0; x < VectorCount; x++)
14801  SearchVector.erase(SearchVector.end() - 1);
14802  Utilities->CallLogPop(290);
14803  return false;
14804  }
14805  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
14806  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
14807  TPrefDirElement SearchElement(NextTrackElement);
14808  SearchElement.TrackVectorPosition = NextPosition;
14809  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
14810  SearchElement.ELinkPos = NextELinkPos;
14811  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
14812  int NextXLinkPos;
14813  if(SearchElement.ELinkPos == 0)
14814  NextXLinkPos = 1;
14815  if(SearchElement.ELinkPos == 1)
14816  NextXLinkPos = 0;
14817  if(SearchElement.ELinkPos == 2)
14818  NextXLinkPos = 3;
14819  if(SearchElement.ELinkPos == 3)
14820  NextXLinkPos = 2;
14821  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14822  {
14823  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14824  // but may be buffers, continuation or gap
14825  SearchElement.XLinkPos = NextXLinkPos;
14826  }
14827 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
14828 // can't set XLink or XLinkPos yet if the element is a leading point.
14829 
14830 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14831  for(unsigned int x = 0; x < SearchVector.size(); x++)
14832  {
14833  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14834  {
14835  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14836  // OK if it's a bridge & routes on different tracks
14837  {
14838  for(int x = 0; x < VectorCount; x++)
14839  SearchVector.erase(SearchVector.end() - 1);
14840  Utilities->CallLogPop(291);
14841  return false;
14842  }
14843  }
14844  }
14845 
14846 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14847  TAllRoutes::TRouteElementPair SecondPair;
14849  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14850  if(RoutePair.first > -1)
14851  {
14852  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14853  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
14854  RoutePair.second).ELinkPos)))
14855  {
14856  // still OK if start of an expected route
14857  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
14858  {
14859  for(int x = 0; x < VectorCount; x++)
14860  SearchVector.erase(SearchVector.end() - 1);
14861  Utilities->CallLogPop(292);
14862  return false; // only allow for start of an expected route
14863  }
14864  }
14865  }
14866  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14867  {
14868  // OK if it's a bridge & routes on different tracks
14869  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
14870  SecondPair.second).ELinkPos)))
14871  {
14872  // still OK if start of an expected route
14873  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
14874  {
14875  for(int x = 0; x < VectorCount; x++)
14876  SearchVector.erase(SearchVector.end() - 1);
14877  Utilities->CallLogPop(293);
14878  return false; // only allow for start of an expected route
14879  }
14880  }
14881  }
14882 
14883 // check if a train on element, unless a bridge & train on different track
14884 // OK of same train as start element - no, drop this
14885 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
14886  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
14887  {
14888  for(int x = 0; x < VectorCount; x++)
14889  SearchVector.erase(SearchVector.end() - 1);
14890  Utilities->CallLogPop(294);
14891  return false;
14892  }
14893  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
14894  {
14895  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
14896  {
14897  for(int x = 0; x < VectorCount; x++)
14898  SearchVector.erase(SearchVector.end() - 1);
14899  Utilities->CallLogPop(295);
14900  return false;
14901  }
14902  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
14903  {
14904  for(int x = 0; x < VectorCount; x++)
14905  SearchVector.erase(SearchVector.end() - 1);
14906  Utilities->CallLogPop(296);
14907  return false;
14908  }
14909  }
14910 
14911 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
14912  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14913  {
14914  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14915  {
14916  for(int x = 0; x < VectorCount; x++)
14917  SearchVector.erase(SearchVector.end() - 1);
14918  Utilities->CallLogPop(297);
14919  return false;
14920  }
14921  }
14922 
14923 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
14924 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
14925 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
14927  {
14928  for(int x = 0; x < VectorCount; x++)
14929  SearchVector.erase(SearchVector.end() - 1);
14930  Utilities->CallLogPop(1689);
14931  return false;
14932  }
14933 
14934 // check if found it
14935  if(SearchElement.TrackVectorPosition == RequiredPosition)
14936  {
14937  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
14938  {
14939  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
14940  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
14941  else
14942  SearchElement.XLinkPos = 1;
14943 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
14944  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
14945  }
14946  SearchVector.push_back(SearchElement);
14947  VectorCount++; // not really needed but include for tidyness
14948  TotalSearchCount++;
14949  Utilities->CallLogPop(298);
14950  return true;
14951  }
14952 // Not the required element - check if a buffer or continuation
14953  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
14954  {
14955  for(int x = 0; x < VectorCount; x++)
14956  SearchVector.erase(SearchVector.end() - 1);
14957  Utilities->CallLogPop(299);
14958  return false;
14959  }
14960 
14961 // check if SearchVector exceeds a size of 150
14962  if(SearchVector.size() > 150)
14963  {
14964  for(int x = 0; x < VectorCount; x++)
14965  SearchVector.erase(SearchVector.end() - 1);
14966  Utilities->CallLogPop(1421);
14967  return false;
14968  }
14969 
14970 // check if reached a leading point
14971  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
14972  {
14973 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
14974  int SearchPos1 = SearchElement.Attribute + 1;
14975  int SearchPos2;
14976  if(SearchPos1 == 2)
14977  SearchPos1++;
14978  if(SearchPos1 == 1)
14979  SearchPos2 = 3;
14980  else
14981  SearchPos2 = 1;
14982 // push element with XLink set to position [SearchPos1]
14983  SearchElement.XLink = SearchElement.Link[SearchPos1];
14984  SearchElement.XLinkPos = SearchPos1;
14985 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
14986  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14987  {
14988  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14989  {
14990  for(int x = 0; x < VectorCount; x++)
14991  SearchVector.erase(SearchVector.end() - 1);
14992  Utilities->CallLogPop(300);
14993  return false;
14994  }
14995  }
14996  SearchVector.push_back(SearchElement);
14997  VectorCount++;
14998  TotalSearchCount++;
14999 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15000 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
15001 // recursive search as has to be a TTrackElement for non-preferred route searches
15002  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
15003  {
15004  Utilities->CallLogPop(301);
15005  return true;
15006  }
15007  else
15008  {
15009 // remove leading point with XLinkPos [SearchPos1]
15010  SearchVector.erase(SearchVector.end() - 1);
15011  VectorCount--;
15012 // push element with XLink set to position [SearchPos2]
15013  SearchElement.XLink = SearchElement.Link[SearchPos2];
15014  SearchElement.XLinkPos = SearchPos2;
15015 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15016  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15017  {
15018  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15019  {
15020  for(int x = 0; x < VectorCount; x++)
15021  SearchVector.erase(SearchVector.end() - 1);
15022  Utilities->CallLogPop(302);
15023  return false;
15024  }
15025  }
15026  SearchVector.push_back(SearchElement);
15027  VectorCount++;
15028  TotalSearchCount++;
15029 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15030  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
15031  {
15032  Utilities->CallLogPop(303);
15033  return true;
15034  }
15035  else
15036  {
15037  for(int x = 0; x < VectorCount; x++)
15038  SearchVector.erase(SearchVector.end() - 1);
15039  Utilities->CallLogPop(304);
15040  return false;
15041  }
15042  }
15043  } // if leading point
15044 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
15045 // ready for next element on route
15046  SearchVector.push_back(SearchElement);
15047  VectorCount++;
15048  TotalSearchCount++;
15049  CurrentTrackElement = SearchElement;
15050  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15051  } // while(true)
15052 }
15053 
15054 // ---------------------------------------------------------------------------
15055 
15057 
15058 /*
15059  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
15060  having all values set (since not necessarily on PrefDirs).
15061  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
15062  (if it was the start), so these are checked first and set if necessary. All elements now have
15063  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
15064  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
15065  to set the route colour and direction graphics.
15066 */
15067 
15068 {
15069  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
15070  if(SearchVector.size() == 0)
15071  {
15072  throw Exception("Error, SearchVector empty");
15073  }
15074 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
15075 // hence need to examine and update it if necessary
15076  TPrefDirElement SecondElement;
15077 
15078  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
15079  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
15080  // need above check or SecondElement will fail
15081  {
15082  SecondElement = SearchVector.at(1);
15083  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
15084  for(int x = 0; x < 4; x++)
15085  {
15086  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
15087  {
15088  if(SearchVector.at(0).XLink == -1) // i.e. not set
15089  {
15090  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
15091  SearchVector.at(0).XLinkPos = x;
15092  }
15093  int ELinkPos;
15094  if(SearchVector.at(0).XLinkPos == 0)
15095  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
15096  // linked to 1st searchvector element, & if XLink was set then x may not correspond
15097  if(SearchVector.at(0).XLinkPos == 1)
15098  ELinkPos = 0;
15099  if(SearchVector.at(0).XLinkPos == 2)
15100  ELinkPos = 3;
15101  if(SearchVector.at(0).XLinkPos == 3)
15102  ELinkPos = 2;
15103  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
15104  {
15105  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
15106  SearchVector.at(0).ELinkPos = ELinkPos;
15107  }
15108  break; // no point going any further
15109  }
15110  }
15111  }
15112  for(unsigned int x = 0; x < SearchVector.size(); x++)
15113  {
15114  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
15115 // set EXNumber
15116  if(!(SearchVector.at(x).EntryExitNumber()))
15117  {
15118  throw Exception("Error in EntryExitNumber 3");
15119  }
15120  SearchVector.at(x).CheckCount++;
15121 // all values now incorporated
15122  }
15123 
15124  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
15125 // This function is only called here for nonsignals routes, so AutoSigsFlag & ConsecSignalsRoute both false
15126 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
15127  Utilities->CallLogPop(305);
15128 }
15129 
15130 // ---------------------------------------------------------------------------
15131 
15133 
15134 /*
15135  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
15136  AutoSigsRoute.
15137  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
15138  beginning or the end.
15139  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15140  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
15141  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
15142  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
15143  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
15144  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15145  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15146 
15147  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
15148  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
15149  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
15150  route at the start.
15151 
15152  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
15153  for the new route and return.
15154 */
15155 
15156 {
15157  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
15158  AnsiString(ReqPosRouteID.GetInt()));
15159  if(SearchVector.size() < 1)
15160  {
15161  Utilities->CallLogPop(306);
15162  return;
15163  }
15164  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
15165  if(!ValidatePrefDir(6))
15166  {
15167  Utilities->CallLogPop(307);
15168  return;
15169  }
15170 
15171  TAllRoutes::TLockedRouteClass LockedRouteObject;
15172 
15174  unsigned int TruncatePrefDirPosition = 0;
15175 
15176  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
15177 /* if have ReqPosRouteID:
15178  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
15179  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15180  then enter the new route into the AllRoutesVector
15181 */
15182  {
15184  {
15185  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
15186  x++) // start at 1 as first element already in SearchVector
15187  {
15189  }
15190  // note that route numbers in map adjusted when ReqPos route cleared
15192  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15193  // set during ClearRouteDuringRouteBuildingAt)
15195  {
15198  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15199  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15200  }
15201  }
15203  {
15204  SearchVector.pop_back();
15205  }
15206  }
15207 
15208  if(StartSelectionRouteID > -1)
15209 /* if have StartSelectionRouteID:
15210  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15211  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15212 */
15213  {
15215  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15216  {
15218  {
15219  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
15220  for(unsigned int x = 0; x < SearchVector.size(); x++)
15221  {
15223  RouteNumber, GetFixedSearchElementAt(7, x));
15224  // find & store locked route truncate position in PrefDirVector for later use
15226  {
15227  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15228  {
15229  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
15230  }
15231  }
15232  }
15234  {
15235  throw Exception("Failed to validate extended route for nonpreferred route");
15236  }
15239  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // ConsecSignalsRoute is false
15240  // now add the reinstated locked route if required and set signals accordingly
15241  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
15242  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
15243  // that I haven't thought of
15245  {
15246  LockedRouteObject.RouteNumber = RouteNumber;
15247  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15248  // now reset the signals for the locked route
15249  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
15250  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15251  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15252  // return all signals to red in route section to be truncated
15253  {
15254  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
15255  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
15256  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15257  {
15258  TrackElement.Attribute = 0;
15259  Track->PlotSignal(11, TrackElement, Display);
15260  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15261  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15262  }
15263  }
15264  }
15265  AllRoutes->CheckMapAndRoutes(3); // test
15266  Utilities->CallLogPop(308);
15267  return;
15268  }
15269  }
15270  else
15271  {
15273  }
15274 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15275 // hence nothing to do here
15276  }
15277 
15278  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
15279  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
15280  {
15281  throw Exception("Failed to validate single route for nonpreferred route");
15282  }
15283  AllRoutes->StoreOneRoute(2, this);
15284  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
15285  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
15286  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
15287  AllRoutes->CheckMapAndRoutes(4); // test
15288  Utilities->CallLogPop(309);
15289 }
15290 
15291 // ---------------------------------------------------------------------------
15292 
15293 void TOneRoute::SetRoutePoints(int Caller) const
15294 /*
15295  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
15296  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
15297  when they were created.
15298 */
15299 {
15300  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
15301  if(!PrefDirVector.empty())
15302  {
15303  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15304  {
15305  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
15306  {
15307  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
15308  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
15309  }
15310  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
15311  {
15312  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
15313  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
15314  }
15315  }
15316  }
15317  Utilities->CallLogPop(327);
15318 }
15319 
15320 // ---------------------------------------------------------------------------
15321 
15322 void TOneRoute::SetRouteSignals(int Caller) const
15323 /* Used for new train additions in AddTrain and in route setting
15324  Set the signals as follows:-
15325  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
15326  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
15327  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
15328  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
15329  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
15330  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
15331  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
15332  of the foregoing are found but there is a further forward linked forward route then the function returns false with
15333  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
15334 
15335  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
15336  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
15337  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
15338  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
15339  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
15340  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
15341  as a green signal.
15342 */
15343 {
15344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
15345  if(!PrefDirVector.empty())
15346  {
15347  // get target Attribute value, check first if there is a forward linked route
15348  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
15349  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
15350  int ForwardLinkedRouteNumber, Attribute = 0;
15351  if(LastElement.Conn[LastElement.XLinkPos] > -1)
15352  // Note that LastElement can't be points but can be linked to points
15353  {
15354  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
15355  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
15356  {
15357  if(ForwardLinkedRouteNumber > -1)
15358  {
15359  int NextForwardLinkedRouteNumber = -1;
15360  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
15361  Attribute)))
15362  {
15363  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
15364  }
15365  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
15366  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
15367  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
15368  }
15369  }
15370  }
15371  int RouteNumber;
15372  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
15373  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
15374  if(RouteType != TAllRoutes::NoRoute)
15375  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
15376  {
15377  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
15378  }
15379  }
15380  Utilities->CallLogPop(1720);
15381 }
15382 
15383 // ---------------------------------------------------------------------------
15384 
15385 bool TOneRoute::PointsToBeChanged(int Caller) const
15386 { // true if at any point in SearchVector points have to be changed
15387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
15388  if(!SearchVector.empty())
15389  {
15390  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
15391  {
15392  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
15393  {
15394  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
15395  {
15396  Utilities->CallLogPop(1717);
15397  return true;
15398  }
15399  }
15400  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
15401  {
15402  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
15403  {
15404  Utilities->CallLogPop(1718);
15405  return true;
15406  }
15407  }
15408  }
15409  }
15410  Utilities->CallLogPop(1719);
15411  return false;
15412 }
15413 
15414 // ---------------------------------------------------------------------------
15415 
15416 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
15417 /*
15418  Works forward through the route until finds:-
15419  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
15420  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
15421  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
15422  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
15423  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
15424  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
15425  returns true;
15426  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
15427 */
15428 {
15429  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
15430  Attribute = 0;
15431  NextForwardLinkedRouteNumber = -1;
15432  for(unsigned int x = 0; x < PrefDirSize(); x++)
15433  {
15434  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
15435  if(PrefDirVector.at(x).TrackType == Bridge)
15436  {
15437  if(PrefDirVector.at(x).XLinkPos < 2)
15438  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15439  else
15440  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15441  }
15442  if(TrainID != -1)
15443  {
15444  Utilities->CallLogPop(328);
15445  return true;
15446  }
15447  if(PrefDirVector.at(x).TrackType == Buffers)
15448  {
15449  Attribute = 1;
15450  Utilities->CallLogPop(329);
15451  return true;
15452  }
15453  if(PrefDirVector.at(x).TrackType == Continuation)
15454  {
15455  Attribute = 3;
15456  Utilities->CallLogPop(330);
15457  return true;
15458  }
15459  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
15460  {
15461  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
15462  {
15463  Attribute = 0;
15464  Utilities->CallLogPop(1950);
15465  return true;
15466  }
15467  }
15468  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
15469  {
15470  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
15471  if(Attribute > 3)
15472  Attribute = 3;
15473  Utilities->CallLogPop(331);
15474  return true;
15475  }
15476  if(x == PrefDirSize() - 1)
15477  {
15478  TPrefDirElement LastElement = PrefDirVector.at(x);
15479  if(LastElement.Conn[LastElement.XLinkPos] > -1)
15480  {
15481  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
15482  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
15483  {
15484  Attribute = 0;
15485  Utilities->CallLogPop(332);
15486  return false;
15487  }
15488  }
15489  }
15490  }
15491  Utilities->CallLogPop(333);
15492  return true;
15493 }
15494 
15495 // ---------------------------------------------------------------------------
15496 
15497 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
15498 /*
15499  This function is only called by TAllRoutes::SetAllRearwardsSignals.
15500 
15501  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
15502  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
15503  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
15504  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
15505  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
15506  a route.
15507 
15508  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
15509  signal. If find a signal (but see note below) set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
15510  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3. On completion Attribute is
15511  passed back from the function as a reference. If no train is found before the beginning of the route is reached the function returns true.
15512 
15513  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
15514  and the next rearwards signal becomes yellow, although it's the first in the route
15515 */
15516 {
15517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
15518  AnsiString(PrefDirVectorStartPosition));
15519  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
15520  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
15521 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
15522 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
15523  bool SkipContinuationAndBufferAttributeChange = false;
15524 
15525  if(!PrefDirVector.empty())
15526  {
15527  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
15528  {
15529  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15530  if(PrefDirPtr->TrackType == Bridge)
15531  {
15532  if(PrefDirPtr->XLinkPos < 2)
15533  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15534  else
15535  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15536  }
15537  if(TrainID != -1)
15538  {
15539  SkipContinuationAndBufferAttributeChange = true;
15540  break;
15541  }
15542  }
15543 
15546  {
15547  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
15548  AutoSigVectorIT++)
15549  {
15550  if(!AllRoutes->AllRoutesVector.empty())
15551  {
15552  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
15553  {
15554  SkipContinuationAndBufferAttributeChange = true;
15555  break;
15556  }
15557  }
15558  }
15559  }
15560 
15562  SkipContinuationAndBufferAttributeChange = true;
15563 
15564  if(!SkipContinuationAndBufferAttributeChange)
15565  {
15566  if(PrefDirVector.back().TrackType == Buffers)
15567  Attribute = 1; // treat buffer as red signal
15568  if(PrefDirVector.back().TrackType == Continuation)
15569  Attribute = 3; // treat continuation as a green signal
15570  }
15571 
15572  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15573  {
15574  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
15575  if(PrefDirPtr->TrackType == Bridge)
15576  {
15577  if(PrefDirPtr->XLinkPos < 2)
15578  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15579  else
15580  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15581  }
15582  if(TrainID != -1)
15583  {
15584  Utilities->CallLogPop(334);
15585  return false;
15586  }
15587  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
15588  // the attribute to 0 so first signal behind the LC is red
15589  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15590  {
15591  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
15592  {
15593  Attribute = 0;
15594  }
15595  }
15596 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
15597 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
15598  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
15599  {
15600  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
15601  PrefDirPtr->ConsecSignals)
15602  {
15603  if(Attribute < 3)
15604  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
15605  else
15606  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
15607  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
15608  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
15609  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
15610  {
15611  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15612  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
15613  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
15614  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
15615  }
15616  if(Attribute < 3)
15617  Attribute++;
15618  Display->Update(); // update after recent plots
15619  }
15620  }
15621  }
15622  }
15623  Utilities->CallLogPop(335);
15624  return true;
15625 }
15626 
15627 // ---------------------------------------------------------------------------
15628 
15629 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, TTruncateReturnType &ReturnFlag)
15630 /*
15631  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
15632  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
15633  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
15634  Selection invalid if a train at or before the truncate point; select a bridge; trying to leave a single element; last element to be left
15635  not a signal (for ConsecSignalsRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
15636  ConsecSignalsRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
15637  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
15638  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
15639 */
15640 {
15641  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
15642  "," + AnsiString((short)ConsecSignalsRoute));
15643  bool ElementInRoute = false;
15644  bool TrainOccupyingRoute = false;
15645 
15646  for(unsigned int b = 0; b < PrefDirSize(); b++)
15647  {
15648  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15649  {
15650  ElementInRoute = true;
15651  break;
15652  }
15653  }
15654  if(!ElementInRoute)
15655  {
15656  ReturnFlag = NotInRoute;
15657  Utilities->CallLogPop(336);
15658  return;
15659  }
15660 // it is in the route so continue, first look for a train or a flashing level crossing
15661  for(int b = PrefDirSize() - 1; b >= 0; b--)
15662  {
15663  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
15664  if(PrefDirVector.at(b).TrackType == Bridge)
15665  {
15666  if(PrefDirVector.at(b).XLinkPos < 2)
15667  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
15668  else
15669  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
15670  }
15671  if(TrainID != -1)
15672  {
15673 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
15674 // ReturnFlag = InRouteFalse;
15675 // Utilities->CallLogPop(337);
15676 // return;
15677 // above removed at v2.1.0 so that routes can be locked when occupied, below added
15678  TrainOccupyingRoute = true; // train is forward of the truncate point
15679  }
15680  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
15681  {
15682  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
15683  ReturnFlag = InRouteFalse;
15684  Utilities->CallLogPop(1941);
15685  return;
15686  }
15687  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
15688  {
15689  break; // OK found truncate element & no flashing LC in front
15690  }
15691  }
15692 
15693  for(unsigned int b = 0; b < PrefDirSize(); b++)
15694  {
15695  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
15696  {
15697  if(PrefDirVector.at(b).TrackType == Bridge)
15698  {
15699  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
15700  ReturnFlag = InRouteFalse;
15701  Utilities->CallLogPop(338);
15702  return;
15703  }
15704  if(b == 1)
15705  {
15706  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
15707  ReturnFlag = InRouteFalse;
15708  Utilities->CallLogPop(339);
15709  return;
15710  }
15711  if(b > 0)
15712  {
15713  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
15714  if(TempElement.ConsecSignals || TempElement.AutoSignals)
15715  {
15716  if(TempElement.Config[TempElement.XLinkPos] != Signal)
15717  {
15718  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
15719  ReturnFlag = InRouteFalse;
15720  Utilities->CallLogPop(340);
15721  return;
15722  }
15723  }
15724  else
15725  {
15726  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
15727  {
15728  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
15729  ReturnFlag = InRouteFalse;
15730  Utilities->CallLogPop(341);
15731  return;
15732  }
15733  }
15734  }
15735 
15736  int RouteNumber;
15738 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
15739 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
15740 
15741 // check if part of this route already locked & disallow if so
15742  if(!(AllRoutes->LockedRouteVector.empty()))
15743  {
15745  {
15746  if(LRVIT->RouteNumber == RouteNumber)
15747  {
15748  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
15749  ReturnFlag = InRouteFalse;
15750  Utilities->CallLogPop(749);
15751  return;
15752  }
15753  }
15754  }
15755 
15756  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
15757  // RouteLockingRequired only checks for trains approaching
15758  {
15761  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
15762  L"Warning!", MB_YESNO | MB_ICONWARNING);
15763  TrainController->BaseTime = TDateTime::CurrentDateTime();
15765  if(button == IDNO)
15766  {
15767  ReturnFlag = InRouteTrue; // still return true even though don't act on it
15768  Utilities->CallLogPop(342);
15769  return;
15770  }
15771  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
15772  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
15773  TAllRoutes::TLockedRouteClass LockedRoute;
15774  bool ExistingLockedRouteModified = false;
15775  LockedRoute.RouteNumber = RouteNumber;
15776  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
15777  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
15778  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
15779  LockedRoute.LockStartTime = TrainController->TTClockTime;
15780 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
15781 // to use the new TruncateTrackVectorPosition & LockStartTime
15782  if(!AllRoutes->LockedRouteVector.empty())
15783  {
15784  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
15785  LRVIT++)
15786  {
15787  if(LRVIT->RouteNumber == RouteNumber)
15788  {
15789  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
15790  LRVIT->LockStartTime = LockedRoute.LockStartTime;
15791  ExistingLockedRouteModified = true;
15792  }
15793  }
15794  }
15795  if(!ExistingLockedRouteModified)
15796  AllRoutes->LockedRouteVector.push_back(LockedRoute);
15797  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
15798  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15799  // return all signals to red in route section to be truncated
15800  {
15801  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
15802  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
15803  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15804  {
15805  TrackElement.Attribute = 0;
15806  Track->PlotSignal(2, TrackElement, Display);
15807  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15808  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15809  }
15810  }
15811 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
15812  ReturnFlag = InRouteTrue;
15813  }
15814  else
15815  {
15816  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
15817  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
15818  {
15819  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
15820  ReturnFlag = InRouteTrue;
15821  }
15822  }
15823  AllRoutes->CheckMapAndRoutes(5); // test
15824  Utilities->CallLogPop(343);
15825  return;
15826  }
15827  }
15828  ReturnFlag = NotInRoute;
15829  Utilities->CallLogPop(344);
15830 }
15831 
15832 // ---------------------------------------------------------------------------
15834 /*
15835  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
15836  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
15837  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
15838  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
15839  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
15840  the route colours.
15841 */
15842 {
15843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
15844  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
15846  int RouteNumber;
15847  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
15848  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
15849 
15850  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
15851  {
15852  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
15853  {
15854  if(PrefDirVector.at(x).TrackType == SignalPost)
15855  {
15856  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
15857  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
15858  }
15859  }
15860  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
15861 // already set all signals to red in route so start at start of route for further rearwards signal setting
15862  }
15863  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
15864  {
15865  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
15866  }
15867  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
15868  AllRoutes->CheckMapAndRoutes(9); // test
15869  TrainController->BaseTime = TDateTime::CurrentDateTime();
15871  Utilities->CallLogPop(345);
15872  return;
15873 }
15874 
15875 // ---------------------------------------------------------------------------
15876 
15877 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
15878 /*
15879  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
15880 */
15881 {
15882  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
15883  AnsiString((short)ConsecSignalsRoute));
15884  if(SearchVector.empty())
15885  {
15886  Utilities->CallLogPop(1149);
15887  return;
15888  }
15889  for(unsigned int b = 0; b < SearchVector.size(); b++)
15890  {
15891  GetModifiableSearchElementAt(1, b).EXGraphicPtr = GetModifiableSearchElementAt(2, b).GetRouteGraphicPtr(AutoSigsFlag, ConsecSignalsRoute);
15893  ConsecSignalsRoute);
15894  }
15895  Utilities->CallLogPop(346);
15896 }
15897 
15898 // ---------------------------------------------------------------------------
15899 
15900 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
15901 /*
15902  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
15903  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
15904  TOneRoute.
15905 */
15906 {
15907  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
15908  AnsiString((short)ConsecSignalsRoute));
15909  RouteFlash.RouteFlashVector.clear();
15910  TRouteFlashElement RouteFlashElement;
15911 
15912  for(unsigned int b = 0; b < SearchVector.size(); b++)
15913  {
15914  int H = GetFixedSearchElementAt(11, b).HLoc;
15915  int V = GetFixedSearchElementAt(12, b).VLoc;
15917  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, ConsecSignalsRoute);
15918  RouteFlashElement.HLoc = H;
15919  RouteFlashElement.VLoc = V;
15921  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
15922  }
15923  Utilities->CallLogPop(348);
15924 }
15925 
15926 // ---------------------------------------------------------------------------
15927 
15928 void TOneRoute::SetLCChangeValues(int Caller, bool ConsecSignalsRoute) //used when setting routes to start any included LC's lowering
15929 {
15930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)ConsecSignalsRoute));
15931  if(!PrefDirVector.empty())
15932  {
15933  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
15934  {
15935  int H = PrefDirPtr->HLoc;
15936  int V = PrefDirPtr->VLoc;
15937  // check for any LCs that are closed to trains & set the flash values and store in the vector
15938  if(Track->IsLCAtHV(39, H, V))
15939  {
15940  if(Track->IsLCBarrierUpAtHV(0, H, V))
15941  {
15942  Track->LCChangeFlag = true;
15943  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
15944  CLC.HLoc = H;
15945  CLC.VLoc = V;
15947  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
15950  CLC.ConsecSignals = ConsecSignalsRoute;
15951  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
15952  Track->ChangingLCVector.push_back(CLC);
15953  }
15954  }
15955  }
15956  }
15957  Utilities->CallLogPop(1948);
15958 }
15959 
15960 // ---------------------------------------------------------------------------
15961 
15963 /*
15964  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
15965  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
15966  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
15967  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
15968 */
15969 {
15970  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
15971  if(!OverlayPlotted)
15972  {
15973  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
15974  {
15975  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
15976  continue;
15977  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
15978  Display->Update();
15979  }
15980  OverlayPlotted = true;
15981  }
15982  Utilities->CallLogPop(349);
15983 }
15984 
15985 // ---------------------------------------------------------------------------
15986 
15988 /*
15989  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
15990  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
15991  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
15992  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
15993 */
15994 {
15995  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
15996  if(OverlayPlotted)
15997  {
15998  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
15999  {
16000  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
16001  continue;
16002  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
16003  Display->Update();
16004  }
16005  OverlayPlotted = false;
16006  }
16007  Utilities->CallLogPop(350);
16008 }
16009 
16010 // ---------------------------------------------------------------------------
16011 
16012 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
16013 {
16014  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
16015  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
16016  {
16017  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
16018  }
16019  Utilities->CallLogPop(120);
16020  return AllRoutesVector.at(At);
16021 }
16022 
16023 // ---------------------------------------------------------------------------
16024 // ---------------------------------------------------------------------------
16025 
16027 {
16028  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
16029  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
16030  {
16031  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
16032  }
16033  Utilities->CallLogPop(121);
16034  return AllRoutesVector.at(At);
16035 }
16036 
16037 // ---------------------------------------------------------------------------
16038 
16039 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
16040 /*
16041  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
16042 */
16043 {
16044  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
16045  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16046  {
16047  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
16048  }
16049  Utilities->CallLogPop(351);
16050 }
16051 
16052 // ---------------------------------------------------------------------------
16053 
16054 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
16055 {
16056  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
16057  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16058  {
16059  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
16060  }
16061  Utilities->CallLogPop(1706);
16062 }
16063 
16064 // ---------------------------------------------------------------------------
16065 
16066 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
16067 /*
16068  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
16069  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
16070  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
16071  the element that matches H & V. If ConsecSignalsRoute ensure only truncate to a signal, else prevent
16072  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
16073  length (train length).
16074 */
16075 {
16076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
16077  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignalsRoute));
16078  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16079  {
16080  TTruncateReturnType ReturnFlag;
16081  RouteTruncateFlag = true;
16082 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
16083  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute, ReturnFlag);
16084  RouteTruncateFlag = false;
16085  if(ReturnFlag == NotInRoute)
16086  continue;
16087  else if(ReturnFlag == InRouteTrue)
16088  {
16089  Utilities->CallLogPop(352);
16090  return true;
16091  }
16092  else if(ReturnFlag == InRouteFalse)
16093  {
16094  Utilities->CallLogPop(353);
16095  return false;
16096  }
16097  }
16098  Utilities->CallLogPop(354);
16099  return false;
16100 }
16101 
16102 // ---------------------------------------------------------------------------
16103 
16104 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
16105 /*
16106  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
16107  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
16108 */
16109 {
16110  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
16111  AnsiString(LinkPos));
16112  if(TrackVectorPosition == -1) // allows for continuation entries & exits
16113  {
16114  Utilities->CallLogPop(355);
16115  return false;
16116  }
16117  THVPair Route2MultiMapKeyPair;
16118 
16119  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
16120  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
16121  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16122  TRoute2MultiMapIterator Route2MultiMapIterator;
16123 
16124  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
16125  {
16126  Utilities->CallLogPop(356);
16127  return false;
16128  }
16129  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
16130  {
16131  Utilities->CallLogPop(1422);
16132  return true;
16133  }
16134  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16135  {
16136  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16137 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16138 // realised after writing this that can't be points as would have been covered above, but leave anyway
16139  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
16140  Route2MultiMapIterator->second.second);
16141  EntryLinkPos = PrefDirElement1.ELinkPos;
16142  ExitLinkPos = PrefDirElement1.XLinkPos;
16143  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16144  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16145  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
16146  {
16147  Utilities->CallLogPop(357);
16148  return true;
16149  }
16150  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
16151  {
16152  Utilities->CallLogPop(358);
16153  return true;
16154  }
16155  }
16156  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
16157  {
16158  Utilities->CallLogPop(1423);
16159  return true;
16160  }
16161  Utilities->CallLogPop(363);
16162  return false; // none found
16163 }
16164 
16165 // ---------------------------------------------------------------------------
16166 
16167 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
16168  Graphics::TBitmap* &EntryDirectionGraphicPtr)
16169 /*
16170  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
16171  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
16172  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
16173  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
16174  for replotting of AutoSigsRoutes.
16175 */
16176 {
16177  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
16178  AnsiString(LinkPos));
16179  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
16180  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
16181  if(TrackVectorPosition == -1)
16182  {
16183  Utilities->CallLogPop(364);
16184  return NoRoute; // allows for continuation entries & exits
16185  }
16186  THVPair Route2MultiMapKeyPair;
16187 
16188  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
16189  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
16190  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16191  TRoute2MultiMapIterator Route2MultiMapIterator;
16192 
16193  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16194  {
16195  Utilities->CallLogPop(365);
16196  return NoRoute; // none found
16197  }
16198  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16199  {
16200  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16201 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16202  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
16203  Route2MultiMapIterator->second.second);
16204  EntryLinkPos = PrefDirElement1.ELinkPos;
16205  ExitLinkPos = PrefDirElement1.XLinkPos;
16206  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16207  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16208  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
16209  {
16210  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
16211  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
16212  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
16213  {
16214  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
16215  }
16216  if(PrefDirElement1.AutoSignals)
16217  {
16218  Utilities->CallLogPop(366);
16219  return AutoSigsRoute;
16220  }
16221  else
16222  {
16223  Utilities->CallLogPop(367);
16224  return NotAutoSigsRoute;
16225  }
16226  }
16227  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
16228  {
16229  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
16230  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
16231  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
16232  {
16233  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
16234  }
16235  if(PrefDirElement1.AutoSignals)
16236  {
16237  Utilities->CallLogPop(368);
16238  return AutoSigsRoute;
16239  }
16240  else
16241  {
16242  Utilities->CallLogPop(369);
16243  return NotAutoSigsRoute;
16244  }
16245  }
16246  }
16247  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16248  {
16249  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16250  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16251 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16252  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
16253  EntryLinkPos = PrefDirElement2.ELinkPos;
16254  ExitLinkPos = PrefDirElement2.XLinkPos;
16255  EntryLink = PrefDirElement2.Link[EntryLinkPos];
16256  ExitLink = PrefDirElement2.Link[ExitLinkPos];
16257  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
16258  {
16259  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
16260  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
16261  {
16262  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
16263  }
16264  if(PrefDirElement2.AutoSignals)
16265  {
16266  Utilities->CallLogPop(370);
16267  return AutoSigsRoute;
16268  }
16269  else
16270  {
16271  Utilities->CallLogPop(371);
16272  return NotAutoSigsRoute;
16273  }
16274  }
16275  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
16276  {
16277  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
16278  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
16279  {
16280  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
16281  }
16282  if(PrefDirElement2.AutoSignals)
16283  {
16284  Utilities->CallLogPop(372);
16285  return AutoSigsRoute;
16286  }
16287  else
16288  {
16289  Utilities->CallLogPop(373);
16290  return NotAutoSigsRoute;
16291  }
16292  }
16293 
16294  ItPair.second--; // the second iterator points one past the last matching value
16295  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
16296  EntryLinkPos = PrefDirElement3.ELinkPos;
16297  ExitLinkPos = PrefDirElement3.XLinkPos;
16298  EntryLink = PrefDirElement3.Link[EntryLinkPos];
16299  ExitLink = PrefDirElement3.Link[ExitLinkPos];
16300  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
16301  {
16302  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
16303  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
16304  {
16305  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
16306  }
16307  if(PrefDirElement3.AutoSignals)
16308  {
16309  Utilities->CallLogPop(374);
16310  return AutoSigsRoute;
16311  }
16312  else
16313  {
16314  Utilities->CallLogPop(375);
16315  return NotAutoSigsRoute;
16316  }
16317  }
16318  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
16319  {
16320  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
16321  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
16322  {
16323  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
16324  }
16325  if(PrefDirElement3.AutoSignals)
16326  {
16327  Utilities->CallLogPop(376);
16328  return AutoSigsRoute;
16329  }
16330  else
16331  {
16332  Utilities->CallLogPop(377);
16333  return NotAutoSigsRoute;
16334  }
16335  }
16336  }
16337  Utilities->CallLogPop(378);
16338  return NoRoute; // none found
16339 }
16340 
16341 // ---------------------------------------------------------------------------
16342 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
16343 /*
16344  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
16345  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
16346 */
16347 {
16348  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
16349  AnsiString(LinkPos));
16350  if(TrackVectorPosition == -1)
16351  {
16352  RouteNumber = -1;
16353  Utilities->CallLogPop(379);
16354  return NoRoute; // allows for continuation & buffer entries & exits
16355  }
16356  THVPair Route2MultiMapKeyPair;
16357 
16358  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
16359  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
16360  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
16361  TRoute2MultiMapIterator Route2MultiMapIterator;
16362 
16363  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16364  {
16365  RouteNumber = -1;
16366  Utilities->CallLogPop(380);
16367  return NoRoute; // none found
16368  }
16369  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16370  {
16371  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16372 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16373  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
16374  Route2MultiMapIterator->second.second);
16375  EntryLinkPos = PrefDirElement1.ELinkPos;
16376  ExitLinkPos = PrefDirElement1.XLinkPos;
16377  EntryLink = PrefDirElement1.Link[EntryLinkPos];
16378  ExitLink = PrefDirElement1.Link[ExitLinkPos];
16379  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
16380  {
16381  RouteNumber = Route2MultiMapIterator->second.first;
16382  if(PrefDirElement1.AutoSignals)
16383  {
16384  Utilities->CallLogPop(381);
16385  return AutoSigsRoute;
16386  }
16387  else
16388  {
16389  Utilities->CallLogPop(382);
16390  return NotAutoSigsRoute;
16391  }
16392  }
16393  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
16394  {
16395  RouteNumber = Route2MultiMapIterator->second.first;
16396  if(PrefDirElement1.AutoSignals)
16397  {
16398  Utilities->CallLogPop(383);
16399  return AutoSigsRoute;
16400  }
16401  else
16402  {
16403  Utilities->CallLogPop(384);
16404  return NotAutoSigsRoute;
16405  }
16406  }
16407  }
16408  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16409  {
16410  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16411  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16412 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
16413  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
16414  EntryLinkPos = PrefDirElement2.ELinkPos;
16415  ExitLinkPos = PrefDirElement2.XLinkPos;
16416  EntryLink = PrefDirElement2.Link[EntryLinkPos];
16417  ExitLink = PrefDirElement2.Link[ExitLinkPos];
16418  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
16419  {
16420  RouteNumber = ItPair.first->second.first;
16421  if(PrefDirElement2.AutoSignals)
16422  {
16423  Utilities->CallLogPop(385);
16424  return AutoSigsRoute;
16425  }
16426  else
16427  {
16428  Utilities->CallLogPop(386);
16429  return NotAutoSigsRoute;
16430  }
16431  }
16432  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
16433  {
16434  RouteNumber = ItPair.first->second.first;
16435  if(PrefDirElement2.AutoSignals)
16436  {
16437  Utilities->CallLogPop(387);
16438  return AutoSigsRoute;
16439  }
16440  else
16441  {
16442  Utilities->CallLogPop(388);
16443  return NotAutoSigsRoute;
16444  }
16445  }
16446 
16447  ItPair.second--; // the second iterator points one past the last matching value
16448  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
16449  EntryLinkPos = PrefDirElement3.ELinkPos;
16450  ExitLinkPos = PrefDirElement3.XLinkPos;
16451  EntryLink = PrefDirElement3.Link[EntryLinkPos];
16452  ExitLink = PrefDirElement3.Link[ExitLinkPos];
16453  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
16454  {
16455  RouteNumber = ItPair.second->second.first;
16456  if(PrefDirElement3.AutoSignals)
16457  {
16458  Utilities->CallLogPop(389);
16459  return AutoSigsRoute;
16460  }
16461  else
16462  {
16463  Utilities->CallLogPop(390);
16464  return NotAutoSigsRoute;
16465  }
16466  }
16467  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
16468  {
16469  RouteNumber = ItPair.second->second.first;
16470  if(PrefDirElement3.AutoSignals)
16471  {
16472  Utilities->CallLogPop(391);
16473  return AutoSigsRoute;
16474  }
16475  else
16476  {
16477  Utilities->CallLogPop(392);
16478  return NotAutoSigsRoute;
16479  }
16480  }
16481  }
16482  RouteNumber = -1;
16483  Utilities->CallLogPop(393);
16484  return NoRoute; // none found
16485 }
16486 
16487 // ---------------------------------------------------------------------------
16488 
16489 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
16490 /*
16491  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
16492  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
16493  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
16494  and Route2MultiMap.
16495 */
16496 {
16497  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
16498  TOneRoute EmptyRoute;
16499 
16500  EmptyRoute.RouteID = NextRouteID;
16501  NextRouteID++;
16502 
16503  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16504  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16505  {
16506  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
16507  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
16508  }
16509  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
16510  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
16511 
16512  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
16513  Utilities->CallLogPop(394);
16514 }
16515 
16516 // ---------------------------------------------------------------------------
16517 
16519 /*
16520  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
16521  that is already in Route is used.
16522 */
16523 {
16524  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
16525  TOneRoute EmptyRoute;
16526 
16527  EmptyRoute.RouteID = Route->RouteID;
16528 
16529  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
16530  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
16531  {
16532  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
16533  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
16534  }
16535  Utilities->CallLogPop(1579);
16536 }
16537 
16538 // ---------------------------------------------------------------------------
16539 
16540 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
16541 /*
16542  When attaching a new route section to an existing route, it is sometimes necessary to erase the
16543  original route and create a new composite route. This function Erases all elements in the route
16544  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
16545  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
16546  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
16547  that are greater than the route number that is removed. The LockedRouteVector as also searched
16548  and if any relate to the route that has been cleared they are erased too, but the fact that one
16549  has been found is recorded so that it can be re-established later.
16550 */
16551 {
16552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
16553  THVPair Route2MultiMapKeyPair;
16554  TRoute2MultiMapEntry Route2MultiMapEntry;
16555  TRoute2MultiMapIterator Route2MultiMapIterator;
16556 
16557 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
16558 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
16559 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
16560 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
16561 // If so the locked route is removed from the locked vector and is lost.
16562  LockedRouteTruncateTrackVectorPosition = 0;
16563  LockedRouteLastTrackVectorPosition = 0;
16564  LockedRouteLastXLinkPos = 0;
16565  LockedRouteLockStartTime = TDateTime(0);
16566  if(!LockedRouteVector.empty())
16567  {
16568  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16569  {
16570  if(LRVIT->RouteNumber == RouteNumber)
16571  {
16572  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
16573  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
16574  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
16575  LockedRouteLockStartTime = LRVIT->LockStartTime;
16576  LockedRouteFoundDuringRouteBuilding = true;
16577  LockedRouteVector.erase(LRVIT);
16578  }
16579  }
16580  }
16581 
16582  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
16583  {
16584  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
16585  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
16586  }
16587  Utilities->CallLogPop(395);
16588 }
16589 
16590 // ---------------------------------------------------------------------------
16591 
16593  TRoute2MultiMapIterator &Route2MultiMapIterator)
16594 /*
16595  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
16596  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
16597  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
16598  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
16599  are given for failure.
16600 */
16601 {
16602  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16603  AnsiString(VLoc) + "," + AnsiString(ELink));
16604  TRouteElementPair ReturnPair;
16605 
16606  ReturnPair.first = -1;
16607  ReturnPair.second = 0;
16608  THVPair Route2MultiMapKeyPair;
16609 
16610  Route2MultiMapKeyPair.first = HLoc;
16611  Route2MultiMapKeyPair.second = VLoc;
16612  TRoute2MultiMapEntry Route2MultiMapEntry;
16613 
16614  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16615  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16616 
16617  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16618  Route2MultiMapIterator = ItPair.first;
16619 
16620  if(ItPair.first == ItPair.second)
16621  {
16622  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
16623  }
16624 
16625  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
16626  {
16627  ReturnPair.first = ItPair.first->second.first;
16628  ReturnPair.second = ItPair.first->second.second;
16629  Route2MultiMapIterator = ItPair.first;
16630  Utilities->CallLogPop(396);
16631  return ReturnPair;
16632  }
16633  ItPair.first++;
16634  if(ItPair.first == ItPair.second)
16635  {
16636  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
16637  }
16638  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
16639  {
16640  ReturnPair.first = ItPair.first->second.first;
16641  ReturnPair.second = ItPair.first->second.second;
16642  Route2MultiMapIterator = ItPair.first;
16643  Utilities->CallLogPop(397);
16644  return ReturnPair;
16645  }
16646  Utilities->CallLogPop(398);
16647  return ReturnPair;
16648 }
16649 
16650 // ---------------------------------------------------------------------------
16651 
16652 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
16653 /*
16654  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
16655  Examines Route2MultiMap and returns true if oa route is found with the passed values of H, V and ELink.
16656  RouteNumber (route position in AllRoutes vector is returned as a reference.
16657  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
16658  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
16659 */
16660 {
16661  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
16662  AnsiString(VLoc) + "," + AnsiString(ELink));
16663  THVPair Route2MultiMapKeyPair;
16664 
16665  Route2MultiMapKeyPair.first = HLoc;
16666  Route2MultiMapKeyPair.second = VLoc;
16667  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
16668 
16669  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16670 
16671  if(ItPair.first == ItPair.second)
16672  {
16673  RouteNumber = -1;
16674  Utilities->CallLogPop(2032);
16675  return false;
16676  }
16677 
16678  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
16679  {
16680  RouteNumber = ItPair.first->second.first;
16681  Utilities->CallLogPop(2033);
16682  return true;
16683  }
16684 
16685  ItPair.first++;
16686 
16687  if(ItPair.first == ItPair.second)
16688  {
16689  RouteNumber = -1;
16690  Utilities->CallLogPop(2034);
16691  return false;
16692  }
16693 
16694  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
16695  {
16696  RouteNumber = ItPair.first->second.first;
16697  Utilities->CallLogPop(2035);
16698  return true;
16699  }
16700  RouteNumber = -1;
16701  Utilities->CallLogPop(2036);
16702  return false;
16703 }
16704 
16705 // ---------------------------------------------------------------------------
16706 
16707 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
16708 /*
16709  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
16710  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
16711  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
16712  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
16713  Called by TAllRoutes::AddRouteElement.
16714 */
16715 {
16716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
16717  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
16718  THVPair Route2MultiMapKeyPair;
16719 
16720  Route2MultiMapKeyPair.first = HLoc;
16721  Route2MultiMapKeyPair.second = VLoc;
16722  TRoute2MultiMapEntry Route2MultiMapEntry;
16723 
16724  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
16725  TRouteElementPair RouteElementPair;
16726 
16727  RouteElementPair.first = RouteNumber;
16728  RouteElementPair.second = RouteElementNumber;
16729  Route2MultiMapEntry.second = RouteElementPair;
16730 
16731  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
16732  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
16733  {
16734  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
16735  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
16736  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
16737  {
16738  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
16739  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
16740  {
16741  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16742  }
16743  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
16744  }
16745  else
16746  // same ELink so have an error
16747  {
16748  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
16749  }
16750  }
16751  else
16752  Route2MultiMap.insert(Route2MultiMapEntry);
16753 // element at H&V not found in map so insert it
16754  Utilities->CallLogPop(399);
16755 }
16756 
16757 // ---------------------------------------------------------------------------
16758 
16760 /*
16761  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
16762  and the second in the reference SecondPair. If there's only one then it's the function return
16763 */
16764 {
16765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
16766  AnsiString(VLoc));
16768 
16769  TempPair.first = -1;
16770  TempPair.second = 0;
16771  SecondPair = TempPair;
16772  TRoute2MultiMapIterator Route2MultiMapIterator;
16773  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
16774  THVPair Route2MultiMapKeyPair;
16775 
16776  Route2MultiMapKeyPair.first = HLoc;
16777  Route2MultiMapKeyPair.second = VLoc;
16778  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
16779  {
16780  Utilities->CallLogPop(400);
16781  return TempPair;
16782  }
16783  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
16784  {
16785  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
16786  Utilities->CallLogPop(401);
16787  return Route2MultiMapIterator->second;
16788  }
16789  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
16790  {
16791  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
16792  TempPair = ItRange.first->second;
16793  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
16794  Utilities->CallLogPop(402);
16795  return TempPair;
16796  }
16797  Utilities->CallLogPop(403);
16798  return TempPair;
16799 }
16800 
16801 // ---------------------------------------------------------------------------
16802 
16803 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
16804 /*
16805  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
16806  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
16807 */
16808 {
16809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
16810  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16811  {
16812  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
16813  {
16814  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
16815  TAllRoutes::TRouteElementPair SecondPair;
16816  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
16817  if(RouteElementPair.first == -1)
16818  // failed to find element in multimap
16819  {
16820  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
16821  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
16822  }
16823  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
16824  // neither pair has expected route number
16825  {
16826  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16827  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
16828  (AnsiString)Caller);
16829  }
16830  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
16831  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
16832  {
16833  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
16834  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
16835  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
16836  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
16837  }
16838  }
16839  }
16840  unsigned int SizeVal = 0;
16841 
16842 // check map and sum of route sizes match
16843  for(unsigned int a = 0; a < AllRoutesSize(); a++)
16844  {
16845  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
16846  }
16847  if(SizeVal != Route2MultiMap.size())
16848  {
16849  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
16850  (AnsiString)Caller);
16851  }
16852  Utilities->CallLogPop(404);
16853  return;
16854 }
16855 
16856 // ---------------------------------------------------------------------------
16857 
16858 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
16859 /*
16860  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
16861  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
16862  exceed that for the erased route. Where this is so the RouteNumber is decremented.
16863 */
16864 {
16865  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
16866  if(!Route2MultiMap.empty())
16867  {
16868  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
16869  {
16870  if(Route2MultiMapIterator->second.first > RouteNumber)
16871  Route2MultiMapIterator->second.first--;
16872  }
16873  }
16874  Utilities->CallLogPop(405);
16875 }
16876 
16877 // ---------------------------------------------------------------------------
16878 
16879 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
16880 /*
16881  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
16882  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
16883  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
16884 */
16885 {
16886  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
16887  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
16888  if(!Route2MultiMap.empty())
16889  {
16890  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
16891  {
16892  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
16893  Route2MultiMapIterator->second.second--;
16894  }
16895  }
16896  Utilities->CallLogPop(406);
16897 }
16898 
16899 // ---------------------------------------------------------------------------
16900 
16901 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
16902 /*
16903  Erases the route element from Route2MultiMap and from the PrefDirVector.
16904  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
16905  decremented if they are greater than the element number removed, and if the entire route is removed
16906  then the route numbers are also decremented in the map for route numbers that are greater than the route
16907  number that is removed.
16908 */
16909 {
16910  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
16911  AnsiString(ELink));
16912  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
16913  TRoute2MultiMapIterator Route2MultiMapIterator;
16914 
16915  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
16916  if(RequiredRoutePair.first == -1)
16917  {
16918  throw Exception("Failed to find route element in RemoveRouteElement");
16919  }
16920  Route2MultiMap.erase(Route2MultiMapIterator);
16921  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
16922 
16923 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
16924  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
16925 
16926  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
16927  {
16928  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
16929  }
16930 
16931 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
16932 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
16933 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
16934 // to check if a route element is present, and the element has already been removed from the map - see above.
16935 
16936 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
16937 /*
16938  int LockedVectorNumber = -1;
16939  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
16940  {
16941  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
16942  }
16943 */
16944 
16945 // erase element from route
16946  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
16947  RequiredRoutePair.second)));
16948 // CheckMapAndRoutes();//test - drop - tested below
16949 
16950 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
16951 // be so as continuation exit is at the end of the route, and truncation is from the end
16953  {
16955  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16956  AutoSigVectorIT--)
16957  {
16958  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
16959  {
16960  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
16961  }
16962  }
16963  }
16964 
16965 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
16966 // and adjust all the corresponding route numbers
16967  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
16968  {
16969  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
16970  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
16971  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
16972 
16973 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
16974  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
16975  it is erased then - see TInterface::ApproachLocking
16976 
16977  if(LockedVectorNumber > -1)
16978  {
16979  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
16980  }
16981 */
16982  // decrement route numbers in the locked route vector whether or not this route is a locked route
16983  if(!LockedRouteVector.empty())
16984  {
16985  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
16986  {
16987  if(LRVIT->RouteNumber > RequiredRoutePair.first)
16988  {
16989  LRVIT->RouteNumber--;
16990  }
16991  }
16992  }
16993 
16995  {
16997  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
16998  AutoSigVectorIT--)
16999  {
17000  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
17001  AutoSigVectorIT->RouteNumber--;
17002  }
17003  }
17004  }
17005  CheckMapAndRoutes(7); // test
17006  Utilities->CallLogPop(407);
17007 }
17008 
17009 // ---------------------------------------------------------------------------
17010 
17011 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
17012 /*
17013  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
17014  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
17015  since that catches all route elements wherever created
17016 */
17017 {
17018  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
17019  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
17020  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
17021  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
17022  Utilities->CallLogPop(408);
17023 }
17024 
17025 // ---------------------------------------------------------------------------
17026 
17027 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
17028 /*
17029  Enter with signal at TrackVectorElement already set to red by the passing train.
17030  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
17031  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
17032  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
17033  case the function sets no further signals.
17034 */
17035 {
17036  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
17037  "," + AnsiString(XLinkPos));
17038  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
17039  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
17040 
17041  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
17042  if(RouteElementPair.first == -1)
17043  {
17044  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
17045  }
17046  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
17047 
17048  RequiredPair = RouteElementPair;
17049  if(RouteElement.XLinkPos != XLinkPos)
17050  {
17051  if(SecondPair.first != -1)
17052  {
17053  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
17054  RequiredPair = SecondPair;
17055  if(RouteElement.XLinkPos != XLinkPos)
17056  {
17057  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
17058  }
17059  }
17060  else
17061  {
17062  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
17063  }
17064  }
17065 
17066 // new function
17067  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
17068  Utilities->CallLogPop(409);
17069 }
17070 
17071 // ---------------------------------------------------------------------------
17072 
17073 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
17074 /*
17075  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
17076  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
17077  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
17078  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
17079  to 2 for successive calls.
17080  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
17081  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
17082  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
17083  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
17084 */
17085 {
17086  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
17087  AnsiString(AccessNumber));
17088  TPrefDirElement RouteElement;
17089  int Attribute = AccessNumber + 1;
17090 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
17091  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
17092 
17093  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
17094  {
17095  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
17096  }
17097  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
17098  {
17099  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
17100  }
17101  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
17102  x).XLinkPos] != End)
17103  {
17104  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
17105  }
17106 // new function
17107  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
17108  Utilities->CallLogPop(410);
17109 }
17110 
17111 // ---------------------------------------------------------------------------
17112 
17113 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
17114 /*
17115  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
17116  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
17117  or (b) in a linked rear route, in which case the function sets no further signals.
17118 
17119  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
17120  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
17121  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
17122  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
17123  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
17124  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
17125  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
17126  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
17127  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
17128  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
17129  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
17130  found behind the train.
17131 
17132  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
17133  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17134  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17135  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
17136  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
17137  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
17138  a route.
17139 
17140  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17141  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
17142  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 and continue working backwards
17143  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
17144  reference. If no train is found before the beginning of the route is reached the function returns true.
17145 
17146 */
17147 {
17148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
17149  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
17150  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
17151  int RearwardLinkedRouteNumber;
17152 
17153  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
17154  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
17155  // signal value in the route for use in further linked routes
17156  {
17157  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
17158  {
17159  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
17160  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17161  {
17162  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
17163  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
17164  break;
17165  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
17166  // flash LCs on those routes
17167  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
17168  }
17169  }
17170  }
17171  else
17172  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
17173  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
17174  {
17175  int TrainID, TrainPosition, BehindTrainPosition;
17176  bool FoundTrain = false, BehindTrain = false;
17177  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
17178  {
17179  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
17180  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
17181  TrainID = TrackElement.TrainIDOnElement;
17182  if(TrackElement.TrackType == Bridge)
17183  {
17184  if(PrefDirElement.XLinkPos < 2)
17185  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17186  else
17187  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17188  }
17189  if(TrainID == -1)
17190  continue;
17191  else
17192  {
17193  FoundTrain = true;
17194  TrainPosition = x;
17195  break;
17196  }
17197  }
17198  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
17199  {
17200  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
17201  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
17202  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
17203  // need the element behind the rearmost train.
17204  {
17205  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
17206  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
17207  TrainID = TrackElement.TrainIDOnElement;
17208  if(TrackElement.TrackType == Bridge)
17209  {
17210  if(PrefDirElement.XLinkPos < 2)
17211  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17212  else
17213  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17214  }
17215  if(TrainID != -1)
17216  continue; // still on train
17217  else
17218  {
17219  BehindTrain = true;
17220  BehindTrainPosition = x;
17221  break;
17222  }
17223  }
17224  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
17225  // so on for as many trains as there are on the single route
17226  {
17227  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
17228  // first signal behind train to be red
17229  }
17230  }
17231  }
17232  Utilities->CallLogPop(411);
17233 }
17234 
17235 // ---------------------------------------------------------------------------
17236 
17237 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
17238 {
17239 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
17240  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
17241  first signal is red, then OK
17242 */
17243  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
17244  AnsiString(RouteTruncatePosition));
17245  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
17246  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
17247  TPrefDirElement PrefDirElement, FirstElement;
17248  TTrackElement TrackElement;
17249  bool ExamineRoute = true;
17250 
17251  while(ExamineRoute)
17252  {
17253  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
17254  {
17255  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
17256  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
17257  TrainID = TrackElement.TrainIDOnElement;
17258  if(TrackElement.TrackType == Bridge)
17259  {
17260  if(PrefDirElement.XLinkPos < 2)
17261  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
17262  else
17263  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
17264  }
17265  if(TrainID > -1)
17266  {
17267  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
17268  { //any trains further back in route will be protected by the red signal behind the stopped train
17269  Utilities->CallLogPop(412);
17270  return false;
17271  }
17272  //added after v2.4.1 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
17273  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
17274  //other way & can cancel the route
17275  {
17276  Utilities->CallLogPop(2203);
17277  return false;
17278  }
17279  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
17280  return true; //TrainOccupyingRoute which is outside this function but also causes route locking)
17281  }
17282  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
17283  {
17284  if(TrackElement.Attribute == 0)
17285  {
17286  Utilities->CallLogPop(413);
17287  return false; // OK, red signal in front of a train
17288  }
17289  SignalCount++;
17290  if(SignalCount >= 3)
17291  {
17292  Utilities->CallLogPop(414);
17293  return false;
17294  }
17295  }
17296  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
17297  // ElinkPos because working back along PrefDir to beginning
17298  {
17299  Utilities->CallLogPop(415);
17300  return false; // test - set to true to create a locked buffer-ended route, false for normal use
17301  }
17302  }
17303  //now look at linked rearwards routes
17304  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
17305  StartPosition = CurrentRoute.PrefDirSize() - 1;
17306  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
17307  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
17308  {
17309  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
17310  ExamineRoute = true;
17311  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
17312  }
17313  else
17314  {
17315  // here check for a train on the element immediately before the first route element
17316  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
17317  TrainID = PriorTrackElement.TrainIDOnElement;
17318  if(PriorTrackElement.TrackType == Bridge)
17319  {
17320  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
17321  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
17322  else
17323  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
17324  }
17325  if(TrainID > -1)
17326  {
17327  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
17328  {
17329  Utilities->CallLogPop(748);
17330  return false;
17331  }
17332  //added after v2.4.1 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
17333  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
17334  //other way & can cancel the route
17335  {
17336  Utilities->CallLogPop(2204);
17337  return false;
17338  }
17339  Utilities->CallLogPop(1962);
17340  return true; //otherwise need to lock the route
17341  }
17342  ExamineRoute = false;
17343  }
17344  }
17345 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
17346 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
17347  Utilities->CallLogPop(416);
17348  return false;
17349 }
17350 
17351 // ---------------------------------------------------------------------------
17352 
17353 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
17354  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
17355 {
17356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
17357  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
17358  TPrefDirElement InternalPrefDirElement; // blank element
17359 
17360  PrefDirElement = InternalPrefDirElement;
17361  if(LockedRouteVector.empty())
17362  {
17363  Utilities->CallLogPop(417);
17364  return false;
17365  }
17366 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
17367 // even if some elements have been removed from the front by a train
17368  bool InLockedRoute = false;
17369 
17370  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17371  {
17372  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
17373  { // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
17374  // doesn't arise)
17375  InLockedRoute = true;
17376  break;
17377  }
17378  }
17379  if(!InLockedRoute)
17380  {
17381  Utilities->CallLogPop(418);
17382  return false;
17383  }
17384 
17385  int RouteNumber, VectorCount = 0;
17386  TRouteType RouteType;
17387 
17388  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17389  {
17390  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
17391  if(RouteType == NoRoute)
17392  continue;
17393  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
17394  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
17395  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
17396  {
17397  throw Exception
17398  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
17399  }
17400  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
17401  {
17402  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
17403  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
17404  {
17405  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
17406  {
17407  PrefDirElement = InternalPrefDirElement;
17408  LockedVectorNumber = VectorCount;
17409  Utilities->CallLogPop(419);
17410  return true;
17411  }
17412  }
17413  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
17414  {
17415  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
17416  {
17417  PrefDirElement = InternalPrefDirElement;
17418  LockedVectorNumber = VectorCount;
17419  Utilities->CallLogPop(420);
17420  return true;
17421  }
17422  else
17423  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
17424  }
17425  }
17426  VectorCount++;
17427  }
17428  Utilities->CallLogPop(421);
17429  return false;
17430 }
17431 
17432 // ---------------------------------------------------------------------------
17433 
17435 {
17436  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
17437  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17438  {
17439  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
17440  {
17441  Utilities->CallLogPop(963);
17442  return x;
17443  }
17444  }
17445  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
17446 }
17447 
17448 // ---------------------------------------------------------------------------
17449 
17451  // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
17452  // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
17453 {
17454  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
17455  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17456  {
17457  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
17458  {
17459  Utilities->CallLogPop(2039);
17460  return true;
17461  }
17462  }
17463  Utilities->CallLogPop(2040);
17464  return false;
17465 }
17466 
17467 // ---------------------------------------------------------------------------
17468 
17470 {
17471  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
17472  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17473  {
17474  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
17475  {
17476  Utilities->CallLogPop(964);
17477  return GetFixedRouteAt(159, x);
17478  }
17479  }
17480  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
17481 }
17482 
17483 // ---------------------------------------------------------------------------
17484 
17486 {
17487  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
17488  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17489  {
17490  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
17491  {
17492  Utilities->CallLogPop(965);
17493  return GetModifiableRouteAt(15, x);
17494  }
17495  }
17496  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
17497 }
17498 
17499 // ---------------------------------------------------------------------------
17500 
17501 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
17502 {
17503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
17504  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
17505  Utilities->SaveFileInt(OutFile, NextRouteID);
17506  for(unsigned int x = 0; x < AllRoutesSize(); x++)
17507  {
17508  TOneRoute OneRoute = GetFixedRouteAt(165, x);
17509  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
17510  OneRoute.SavePrefDirVector(6, OutFile);
17511  }
17512  Utilities->CallLogPop(1442);
17513 }
17514 
17515 // ---------------------------------------------------------------------------
17516 
17517 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
17518 {
17519  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
17520  int NumberOfRoutes;
17521 
17522  NumberOfRoutes = Utilities->LoadFileInt(InFile);
17523  NextRouteID = Utilities->LoadFileInt(InFile);
17524  for(int x = 0; x < NumberOfRoutes; x++)
17525  {
17526  TOneRoute OneRoute; // empty route
17527  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
17528  OneRoute.LoadPrefDir(2, InFile);
17530  {
17531  StoreOneRouteAfterSessionLoad(0, &OneRoute);
17532  }
17533  else
17534  {
17535  Utilities->CallLogPop(1443);
17536  return false;
17537  }
17538  }
17539  Utilities->CallLogPop(1444);
17540  return true;
17541 }
17542 
17543 // ---------------------------------------------------------------------------
17544 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
17545 {
17546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
17547  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
17548 
17549  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
17550  {
17551  Utilities->CallLogPop(1445);
17552  return false;
17553  }
17554  int NextID = Utilities->LoadFileInt(InFile);
17555 
17556  if((NextID < 0) || (NextID > 1000000))
17557  {
17558  Utilities->CallLogPop(1446);
17559  return false;
17560  }
17561  for(int x = 0; x < NumberOfRoutes; x++)
17562  {
17563  int RouteID = Utilities->LoadFileInt(InFile);
17564  if((RouteID < 0) || (RouteID > 20000))
17565  {
17566  Utilities->CallLogPop(1447);
17567  return false;
17568  }
17569  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
17570  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
17571  {
17572  Utilities->CallLogPop(1448);
17573  return false;
17574  }
17575  }
17576  Utilities->CallLogPop(1449);
17577  return true;
17578 }
17579 
17580 // ---------------------------------------------------------------------------
17581 
17582 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
17583 { // return true for a loop
17584  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
17585  AnsiString(StartPosition));
17586  if(EndPosition == StartPosition)
17587  {
17588  Utilities->CallLogPop(1839);
17589  return true; // shouldn't happen but treat as a loop if does
17590  }
17591 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
17592  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
17593  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
17594 
17595  while(TrackIsInARoute(15, TVPos, LkPos))
17596  {
17597  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
17598  int NewLkPos = -1;
17599  if(NewTVPos > -1)
17600  {
17601  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
17602  if(NewLkPos == -1)
17603  {
17604  Utilities->CallLogPop(1840);
17605  return true; // shouldn't arise but treat as loop if does
17606  }
17607  }
17608  else // reached a buffer or continuation
17609  {
17610  Utilities->CallLogPop(1841);
17611  return false;
17612  }
17613 //Error found by Xeon notified by email 13/10/20.
17614 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
17615 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
17616 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
17617 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
17618 //New check added for v2.6.0
17619 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
17620 //as possible in case there are other unforeseen effects.
17621  int RouteNumber; //dummy, not used
17622  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
17623  {
17624  Utilities->CallLogPop(2241);
17625  return false;
17626  }
17627  //now make the connected element the current element, read across the TV number and determine the exit link
17628  TVPos = NewTVPos;
17629  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
17630  {
17631  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
17632  {
17633  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
17634  LkPos = 1;
17635  else
17636  LkPos = 3;
17637  }
17638  else
17639  LkPos = 0;
17640  }
17641  else
17642  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
17643  if(TVPos == StartPosition)
17644  {
17645  Utilities->CallLogPop(1842);
17646  return true; // it is a loop
17647  }
17648  }
17649  Utilities->CallLogPop(1843);
17650  return false; // reached end of route so not a loop
17651 }
17652 
17653 // ---------------------------------------------------------------------------
17654 
17655 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17656 /*
17657  Track geometry allows diagonals to cross without occupying the same track element, so when
17658  route plotting it is necessary to check if there is an existing route or a train on such a crossing
17659  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
17660  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17661  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17662  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17663  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17664  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17665  Each of these is examined in turn for each route element in the relevant position.
17666 
17667  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
17668  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
17669  that returns false in all cases (including elements & links not present) except train present.
17670 */
17671 {
17672  int TrainID; // not used in this function
17673 
17674  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
17675  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
17676  TPrefDirElement TempPrefDirElement;
17677  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17678 
17679  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
17680  if(FirstPair.first > -1)
17681  {
17682  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
17683  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17684  {
17685  Utilities->CallLogPop(310);
17686  return true;
17687  }
17688  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17689  {
17690  Utilities->CallLogPop(311);
17691  return true;
17692  }
17693  }
17694  if(SecondPair.first > -1)
17695  {
17696  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
17697  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17698  {
17699  Utilities->CallLogPop(312);
17700  return true;
17701  }
17702  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17703  {
17704  Utilities->CallLogPop(313);
17705  return true;
17706  }
17707  }
17708 
17709  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
17710  9, TrainID)))
17711  {
17712  Utilities->CallLogPop(1997);
17713  return true;
17714  }
17715 
17716  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
17717  if(FirstPair.first > -1)
17718  {
17719  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
17720  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17721  {
17722  Utilities->CallLogPop(314);
17723  return true;
17724  }
17725  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17726  {
17727  Utilities->CallLogPop(315);
17728  return true;
17729  }
17730  }
17731  if(SecondPair.first > -1)
17732  {
17733  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
17734  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17735  {
17736  Utilities->CallLogPop(316);
17737  return true;
17738  }
17739  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17740  {
17741  Utilities->CallLogPop(317);
17742  return true;
17743  }
17744  }
17745 
17746  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
17747  9, TrainID)))
17748  {
17749  Utilities->CallLogPop(1998);
17750  return true;
17751  }
17752 
17753  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
17754  if(FirstPair.first > -1)
17755  {
17756  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
17757  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17758  {
17759  Utilities->CallLogPop(318);
17760  return true;
17761  }
17762  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17763  {
17764  Utilities->CallLogPop(319);
17765  return true;
17766  }
17767  }
17768  if(SecondPair.first > -1)
17769  {
17770  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
17771  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17772  {
17773  Utilities->CallLogPop(320);
17774  return true;
17775  }
17776  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17777  {
17778  Utilities->CallLogPop(321);
17779  return true;
17780  }
17781  }
17782 
17783  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
17784  7, TrainID)))
17785  {
17786  Utilities->CallLogPop(1999);
17787  return true;
17788  }
17789 
17790  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
17791  if(FirstPair.first > -1)
17792  {
17793  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
17794  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17795  {
17796  Utilities->CallLogPop(322);
17797  return true;
17798  }
17799  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17800  {
17801  Utilities->CallLogPop(323);
17802  return true;
17803  }
17804  }
17805  if(SecondPair.first > -1)
17806  {
17807  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
17808  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17809  {
17810  Utilities->CallLogPop(324);
17811  return true;
17812  }
17813  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17814  {
17815  Utilities->CallLogPop(325);
17816  return true;
17817  }
17818  }
17819 
17820  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
17821  3, TrainID)))
17822  {
17823  Utilities->CallLogPop(2000);
17824  return true;
17825  }
17826 
17827  Utilities->CallLogPop(326);
17828  return false;
17829 }
17830 
17831 // ---------------------------------------------------------------------------
17832 
17833 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
17834 /*
17835  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
17836  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
17837  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
17838  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
17839  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
17840  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
17841  Each of these is examined in turn for each route element in the relevant position.
17842 */
17843 {
17844  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17845  "," + AnsiString(DiagonalLinkNumber));
17846  TPrefDirElement TempPrefDirElement;
17847  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
17848 
17849  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
17850  if(FirstPair.first > -1)
17851  {
17852  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
17853  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17854  {
17855  Utilities->CallLogPop(2010);
17856  return true;
17857  }
17858  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17859  {
17860  Utilities->CallLogPop(2011);
17861  return true;
17862  }
17863  }
17864  if(SecondPair.first > -1)
17865  {
17866  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
17867  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17868  {
17869  Utilities->CallLogPop(2012);
17870  return true;
17871  }
17872  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17873  {
17874  Utilities->CallLogPop(2013);
17875  return true;
17876  }
17877  }
17878 
17879  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
17880  if(FirstPair.first > -1)
17881  {
17882  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
17883  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17884  {
17885  Utilities->CallLogPop(2014);
17886  return true;
17887  }
17888  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17889  {
17890  Utilities->CallLogPop(2015);
17891  return true;
17892  }
17893  }
17894  if(SecondPair.first > -1)
17895  {
17896  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
17897  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17898  {
17899  Utilities->CallLogPop(2016);
17900  return true;
17901  }
17902  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
17903  {
17904  Utilities->CallLogPop(2017);
17905  return true;
17906  }
17907  }
17908 
17909  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
17910  if(FirstPair.first > -1)
17911  {
17912  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
17913  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17914  {
17915  Utilities->CallLogPop(2018);
17916  return true;
17917  }
17918  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17919  {
17920  Utilities->CallLogPop(2019);
17921  return true;
17922  }
17923  }
17924  if(SecondPair.first > -1)
17925  {
17926  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
17927  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17928  {
17929  Utilities->CallLogPop(2020);
17930  return true;
17931  }
17932  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
17933  {
17934  Utilities->CallLogPop(2021);
17935  return true;
17936  }
17937  }
17938 
17939  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
17940  if(FirstPair.first > -1)
17941  {
17942  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
17943  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17944  {
17945  Utilities->CallLogPop(2022);
17946  return true;
17947  }
17948  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17949  {
17950  Utilities->CallLogPop(2023);
17951  return true;
17952  }
17953  }
17954  if(SecondPair.first > -1)
17955  {
17956  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
17957  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
17958  {
17959  Utilities->CallLogPop(2024);
17960  return true;
17961  }
17962  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
17963  {
17964  Utilities->CallLogPop(2025);
17965  return true;
17966  }
17967  }
17968 
17969  Utilities->CallLogPop(2026);
17970  return false;
17971 }
17972 
17973 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:7640
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:676
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:476
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:16104
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1181
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:915
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:463
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:10220
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:662
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:729
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:612
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:564
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:10193
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:351
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:485
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:352
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:874
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:4943
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11675
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:771
TFixedTrackPiece
Definition: TrackUnit.h:80
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:107
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1582
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12764
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:182
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:696
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:408
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:906
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6713
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:16707
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:90
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:790
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:907
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:8880
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:792
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:17113
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:918
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1239
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:508
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:688
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:580
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:701
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:11934
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:758
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:619
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:703
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:349
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11715
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:678
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3579
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:699
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:394
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:453
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:14179
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:686
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:289
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6566
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1500
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:466
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:683
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1562
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:624
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5079
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5106
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1385
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:505
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1523
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:64
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:825
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:846
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1645
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:741
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:9192
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:532
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:15416
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:611
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:904
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:17833
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:351
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1553
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:523
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2449
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:483
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:470
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5235
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:727
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:671
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:459
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:149
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7356
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1395
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:384
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:561
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:16540
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:762
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:497
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:665
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:11472
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:359
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6859
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:482
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:400
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8624
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:8377
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12565
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14000
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:565
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:16901
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:856
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:854
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:493
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1504
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:872
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:547
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:11276
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:156
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:512
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4005
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3264
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:672
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:830
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1407
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:458
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:581
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:759
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:465
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:795
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7173
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:357
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:164
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:661
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:584
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4164
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1195
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:9626
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:653
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:516
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:867
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3140
Unused
@ Unused
Definition: TrackUnit.h:63
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:586
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:616
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1194
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:489
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:704
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:17353
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2480
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:769
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:252
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17544
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:493
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8534
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1561
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1405
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1491
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:219
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:916
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:660
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:355
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:819
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2868
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:15928
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:776
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:668
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:499
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Definition: TrackUnit.cpp:7597
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11538
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:690
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:443
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:477
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:793
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2496
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:626
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1004
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:16652
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:774
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:818
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:424
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1227
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:705
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11766
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1453
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:594
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5195
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:669
TTrain
Definition: TrainUnit.h:271
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:313
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:12432
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:503
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:96
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:151
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:10234
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:492
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:560
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int ConsecSignals, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:5765
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:489
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:841
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:542
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6874
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:415
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:346
GapJump
@ GapJump
Definition: TrackUnit.h:63
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:442
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:789
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:17011
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:15877
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:855
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:147
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:471
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:919
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:457
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:147
TTrack::Raising
@ Raising
Definition: TrackUnit.h:523
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:627
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:487
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:9261
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:557
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1409
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1373
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:15900
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:697
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:365
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:633
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:499
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:692
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:385
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:760
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:452
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:714
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1271
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5426
End
@ End
Definition: TrackUnit.h:73
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1411
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:667
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:842
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers
Definition: TrackUnit.h:534
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:7801
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:863
TTrack::LCFoundInAutoSigsRouteMessageGiven
bool LCFoundInAutoSigsRouteMessageGiven
true if message given to user, to avoid giving multiple times and to avoid other failure messages bei...
Definition: TrackUnit.h:651
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:902
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:482
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:9367
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1017
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:295
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:799
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:639
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:698
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:577
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:912
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:123
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:722
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:491
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:757
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3423
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:988
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:754
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:989
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:524
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:700
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8499
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:998
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:461
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:16054
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:421
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:777
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:863
TTrack::TActiveLevelCrossing::ConsecSignals
int ConsecSignals
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:530
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1527
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:791
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:826
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6888
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:456
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
Definition: TrackUnit.h:583
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:403
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6170
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:254
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:490
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:684
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:7839
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:905
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:816
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:16039
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:755
Concourse
@ Concourse
Definition: TrackUnit.h:64
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:656
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:707
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:800
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:72
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:12222
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:11960
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:202
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:713
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:803
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:62
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:502
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4089
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1597
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:427
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:813
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:433
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:828
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:480
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:593
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:803
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:349
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:494
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:672
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:472
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:92
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:430
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:815
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:574
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:9811
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:16858
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:15629
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4322
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:156
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1616
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:673
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:788
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:923
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:477
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:585
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:719
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:834
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:382
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
Definition: TrackUnit.cpp:10047
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:17450
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:505
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1015
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:610
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2464
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:709
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1417
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:6845
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:13462
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6594
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7787
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:6673
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:666
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:720
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:607
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:659
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:598
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1197
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:754
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:802
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:509
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:801
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:469
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:11850
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:765
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:866
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:11025
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1528
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1580
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:903
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:587
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:11505
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:13044
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:651
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:15833
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3241
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:141
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:11913
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:10094
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:9499
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1499
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:763
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:815
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:532
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:495
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:496
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5289
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:813
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:11325
Under
@ Under
Definition: TrackUnit.h:73
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:449
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:15385
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:707
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:695
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:538
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:131
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2517
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:10246
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:10568
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:870
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:346
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:133
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:117
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:9402
Lead
@ Lead
Definition: TrackUnit.h:73
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5154
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1533
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:12159
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:772
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:527
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3449
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:217
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:4986
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (ConsecSignals == 2) and returns the v...
Definition: TrackUnit.cpp:5746
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:83
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1230
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:8311
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:467
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:468
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:578
TTrack::Up
@ Up
Definition: TrackUnit.h:523
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:862
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:709
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:500
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
Definition: TrackUnit.cpp:9381
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:922
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1367
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:339
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7754
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1521
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:649
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:215
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1511
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:362
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:780
Crossover
@ Crossover
Definition: TrackUnit.h:63
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all ConsecSignals values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:5633
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:474
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:445
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:711
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:622
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:7700
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:782
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6622
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:8853
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:451
Signal
@ Signal
Definition: TrackUnit.h:73
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:487
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:505
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:460
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:679
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:16342
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:151
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1261
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:11375
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:505
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:9988
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4173
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:485
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:9354
TGraphicElement::Width
int Width
Definition: TrackUnit.h:353
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:17237
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:519
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:17434
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:16167
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:684
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:487
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:726
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:569
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:446
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3733
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:468
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:770
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:570
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3711
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2058
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:605
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:464
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:8435
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:11156
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:588
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:406
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:861
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:842
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5130
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17517
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:567
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1409
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:909
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:768
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1398
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:827
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6331
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:470
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:653
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1028
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1030
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:513
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7050
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:15987
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:571
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:421
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6695
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:784
Erase
@ Erase
Definition: TrackUnit.h:64
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:831
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:397
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:479
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:4810
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:707
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1560
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:123
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:811
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:858
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:575
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:11981
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:9901
Parapet
@ Parapet
Definition: TrackUnit.h:64
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:447
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:16012
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:785
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:992
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:277
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8120
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:15962
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:377
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:851
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:707
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:16879
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:590
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:914
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:682
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:783
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:145
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:478
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:806
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:241
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:549
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1033
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:634
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:798
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:13615
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:823
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:135
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:217
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:10122
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:11083
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:504
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1175
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:496
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:596
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:475
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:731
TTrack
Definition: TrackUnit.h:463
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1238
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:754
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1245
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:17027
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1498
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7325
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:620
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:503
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:840
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:650
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:726
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:849
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:126
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:805
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:515
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:685
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:215
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:16518
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:223
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2596
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:450
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7940
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:908
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:5527
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1823
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:131
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:502
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:724
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:156
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:844
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:690
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2281
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:213
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1496
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7022
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:481
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:10871
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11628
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:501
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1373
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:9291
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:7663
IDInt
Definition: TrackUnit.h:412
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2281
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:573
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:17485
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:597
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:778
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3980
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:9101
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:4585
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:143
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:792
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:772
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:821
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:355
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:17582
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:894
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:8236
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:121
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:485
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:95
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:6971
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1176
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:221
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:151
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:885
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:668
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:730
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:380
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:631
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:221
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:392
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:847
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1565
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:154
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:128
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:767
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6939
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:544
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:808
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:781
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:715
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:145
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:788
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:754
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1384
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:838
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1502
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:835
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1512
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:436
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4244
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:570
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Definition: TrackUnit.cpp:8059
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:639
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:13983
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1203
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:716
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:349
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:12087
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:812
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1182
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:149
Points
@ Points
Definition: TrackUnit.h:63
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:702
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:13498
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:723
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:16592
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:853
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:8784
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:9971
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:409
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:582
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:820
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:498
Trail
@ Trail
Definition: TrackUnit.h:73
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:8293
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:15497
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:761
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1569
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:497
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:804
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:15322
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:817
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:647
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:418
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:725
Continuation
@ Continuation
Definition: TrackUnit.h:63
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1024
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:6818
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:47
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3341
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5366
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:355
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:8340
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:852
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:860
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:868
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:10914
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:491
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:822
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:752
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:857
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:349
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:505
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1013
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2958
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:353
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:873
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1401
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:85
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:455
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:688
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:609
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:636
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1559
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:910
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:368
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:271
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:728
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:294
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:836
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:17655
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:486
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:11814
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1002
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:484
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:766
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1375
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1006
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:349
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:448
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:674
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:615
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:782
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4229
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:871
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:16489
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1592
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:698
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:121
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:576
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:694
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:652
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:198
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:9765
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:810
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:617
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1240
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:17501
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:495
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1579
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4214
Connection
@ Connection
Definition: TrackUnit.h:73
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3318
TPrefDirElement::ConsecSignals
bool ConsecSignals
marker within the route for ConsecSignalsRoute element
Definition: TrackUnit.h:256
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:358
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1567
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:8552
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:993
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:732
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:500
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:15132
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:10745
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:706
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:809
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:7727
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:859
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1011
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16803
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:16759
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6404
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:460
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:9652
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:691
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:850
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:630
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1228
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:882
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:485
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5174
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:843
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:707
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:444
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:254
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:349
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:661
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:8907
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:487
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:632
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:643
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:16026
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4354
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:787
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2384
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:674
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6899
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:386
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2724
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:374
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:839
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:130
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:864
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:371
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:15293
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:540
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:12339
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:265
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:348
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:659
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:589
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:606
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:613
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:393
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:488
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1176
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:565
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:462
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:575
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:898
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:624
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:10325
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:454
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:349
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:514
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:917
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:98
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool ConsecSignalsRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:828
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1371
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:210
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:797
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int ConsecSignals, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6478
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1477
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:7879
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:625
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:571
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:621
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:12058
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:17469
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:139
TTrack::TBarrierState
TBarrierState
< state of barriers
Definition: TrackUnit.h:522
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1237
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4136
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:700
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4106
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1670
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:525
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1019
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set ConsecSignals value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:5673
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:990
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:694
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:824
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:626
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:6650
Platform
@ Platform
Definition: TrackUnit.h:63
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1245
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:223
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:577
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:869
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:665
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:635
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4131
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:676
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1506
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1026
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:764
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:920
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7278
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:664
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1189
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:794
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:829
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8473
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1000
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:753
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:9866
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1484
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:814
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:623
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1373
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:347
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:702
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:147
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:779
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:141
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:677
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1375
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:527
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:5689
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:708
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3218
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:756
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:642
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:98
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:111
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:498
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:786
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:647
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9798
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:773
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:865
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:833
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:147
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:593
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:911
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:251
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:693
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:536
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:712
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:850
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:412
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:566
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:87
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:14750
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:600
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:705
RouteCall
@ RouteCall
Definition: TrackUnit.h:1182
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:387
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:10259
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:845
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:250
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:591
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:501
NotSet
@ NotSet
Definition: TrackUnit.h:73
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
concourses, non-station named locations & parapets)
Definition: TrackUnit.h:581
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:16066
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:17073
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:213
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:390
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:592
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:579
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9827
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:9163
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:588
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:505
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:213
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:775
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:913
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5591
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:156
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:64
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:921
TRailGraphics::smTransparent
Graphics::TBitmap * smTransparent
Definition: GraphicUnit.h:887
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:641
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:10271
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1242
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:391
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:141
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1243
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:837
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:721
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:807
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:692
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:487
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:614
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:9154
Bridge
@ Bridge
Definition: TrackUnit.h:63
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:848
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:439
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1176
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:796
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:523
Gap
@ Gap
Definition: TrackUnit.h:73
Buffers
@ Buffers
Definition: TrackUnit.h:63
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:15056
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:689
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:73
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:10283
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:14394
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:473
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4044
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:10206
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:832